2010-07-04 64 views

回答

7

只有這樣,才能安全地檢查一個類型是否是程序集的一部分是檢查包含它的名稱,版本,文化和公共密鑰(如果已簽名)的程序集的完全限定名稱。所有.Net基本類庫(BCL)都由Microsoft使用其私鑰進行簽名。這使得其他人幾乎不可能創建一個具有與基類庫相同的完全限定名稱的程序集。

//add more .Net BCL names as necessary 
var systemNames = new HashSet<string> 
{ 
"mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 
"System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" 
}; 

var isSystemType = systemNames.Contains(objToTest.GetType().Assembly.FullName); 

稍微較不脆的解決方案是使用AssemblyName類和跳過的版本號/培養檢查。這當然假定公鑰在版本之間不會改變。

//add more .Net BCL names as necessary 
var systemNames = new List<AssemblyName> 
{ 
new AssemblyName ("mscorlib, Version=4.0.0.0, Culture=neutral, " + 
        "PublicKeyToken=b77a5c561934e089"), 
new AssemblyName ("System.Core, Version=4.0.0.0, Culture=neutral, "+ 
        "PublicKeyToken=b77a5c561934e089") 
}; 

var obj = GetObjectToTest(); 

var objAN = new AssemblyName(obj.GetType().Assembly.FullName); 

bool isSystemType = systemNames.Any(
     n => n.Name == objAN.Name 
      && n.GetPublicKeyToken().SequenceEqual(objAN.GetPublicKeyToken())); 

BCL的大部分已經用相同的密鑰但不是全部簽名。您可以使用AssemblyName類來檢查公鑰標記。這取決於你的需求。

4

您可以檢查聲明類型的組件。

object.GetType().Assembly 
+3

所以問題就是:如何知道程序集是.NET框架的一部分? – 2010-07-04 17:04:38

5

如果你只是想MyClassstring來區分,那麼你可以直接檢查這些類型:

Type typeToTest = GetTypeFromSomewhere(); 

if (typeToTest == typeof(MyClass)) 
    MyClassAction(); 
else if (typeToTest == typeof(string)) 
    StringAction(); 
else 
    NotMyClassOrString(); 

如果你需要一個給定的類型是否是一個框架,一個更一般的檢查鍵入那麼你可以檢查它是否屬於System命名空間:

// create an array of the various public key tokens used by system assemblies 
byte[][] systemTokens = 
    { 
     typeof(System.Object) 
      .Assembly.GetName().GetPublicKeyToken(), // B7 7A 5C 56 19 34 E0 89 
     typeof(System.Web.HttpRequest) 
      .Assembly.GetName().GetPublicKeyToken(), // B0 3F 5F 7F 11 D5 0A 3A 
     typeof(System.Workflow.Runtime.WorkflowStatus) 
      .Assembly.GetName().GetPublicKeyToken() // 31 BF 38 56 AD 36 4E 35 
    }; 

Type typeToTest = GetTypeFromSomewhere(); 

string ns = typeToTest.Namespace; 
byte[] token = typeToTest.Assembly.GetName().GetPublicKeyToken(); 

bool isSystemType = ((ns == "System") || ns.StartsWith("System.")) 
        && systemTokens.Any(t => t.SequenceEqual(token)); 
+0

不是真正的防彈,例如,如果名稱空間被稱爲「SystemUtil」;) – 2010-07-04 17:52:11

+0

@thomas:我意識到發佈後不久,但在我可以編輯之前被叫走。現在修復。 – LukeH 2010-07-04 20:59:48

+0

我很肯定你實際上可以編寫你自己的程序集並且創建命名空間'System。[something]'...我不是很喜歡這樣做,但是我知道一些開源項目可以做 - 例如,['System.Data.SQLite'](http://sqlite.phxsoftware.com/),['System.Drawing.Html'](http://htmlrenderer.codeplex.com/)。 – 2010-07-04 21:27:07

0

並非所有框架類的Sys系統啓動tem命名空間(他們也可以是微軟等)。

因此,你很可能與該類型的您正在測試,例如比較已知框架類的位置:

if (String.CompareOrdinal(
     Path.GetDirectoryName(typeof(String).Assembly.Location), 
     Path.GetDirectoryName(typeof(MyType).Assembly.Location) 
    ) == 0) 
    { 
    //Framework Type 
    } 
    else 
    { 
    //3rd Party DLL 
    } 

不是最大的解決方案;但比僅僅測試命名空間是否以System開頭(我可以創建一個以不是框架類的System開頭的命名空間)更安全。

編輯

此外,除了上述試驗,不會傷害驗證類型從全局程序集緩存加載:

typeof(MyType).Assembly.GlobalAssemblyCache 
+2

據我所知,BCL只包含'System。*'命名空間。 「Microsoft。*」命名空間是BCL的超集 - 有時稱爲FCL - 並不屬於ECMA CLI標準的一部分。 http://en.wikipedia.org/wiki/Base_Class_Library – LukeH 2010-07-04 21:10:14

+0

@LukeH:真的很好。我要做的重要一點是不要依賴以System開頭的命名空間。正如其他解決方案所表明的那樣,表達永遠是最好的選擇。這是一個「窮人」的檢查,我認爲我會拋出以防萬一。 – 2010-07-05 13:10:22

1

檢查裝配屬於CLR庫:

myType.Module.ScopeName == "CommonLanguageRuntimeLibrary" 

的解釋here