如何确定System.Type是自定义类型还是Framework类型?
我想清楚地确定我所拥有的类型是自定义类类型(MyClass)还是Framework(System.String)提供的类型。
反思是否有任何方法可以将我的类类型与system.string或其他Framework提供的类型区分开来?
安全检查类型是否为程序集的一部分的唯一方法是检查程序集的完全限定名称,该名称包含其名称,版本,区域性和公钥(如果已签名)。 所有.Net基类库(BCL)都由Microsoft使用其私钥签名。 这使得其他任何人几乎不可能创建具有与基类库相同的完全限定名称的程序集。
//add more .Net BCL names as necessary var systemNames = new HashSet { "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 { 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类来检查公钥令牌。 这取决于您的需求。
如果您只是想区分MyClass
和string
那么您可以直接检查这些类型:
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));
您可以检查声明类型的程序集。
object.GetType().Assembly
检查程序集是否属于CLR库:
myType.Module.ScopeName == "CommonLanguageRuntimeLibrary"
如此处所述。
并非所有框架类都在System命名空间中启动(它们也可以是Microsoft等)。
因此,您可以将已知框架类的位置与您正在测试的类型的位置进行比较,例如:
if (String.CompareOrdinal( Path.GetDirectoryName(typeof(String).Assembly.Location), Path.GetDirectoryName(typeof(MyType).Assembly.Location) ) == 0) { //Framework Type } else { //3rd Party DLL }
不是最好的解决方案; 但是比测试命名空间是否以System开头更安全(我可以创建一个以System不是框架类开头的命名空间)。
编辑
此外,除了上述测试之外,validation从全局程序集缓存加载类型也没有问题:
typeof(MyType).Assembly.GlobalAssemblyCache