如何确定System.Type是自定义类型还是Framework类型?

时间:2010-07-04 14:10:45

标签: c# reflection types

我想清楚地确定我所拥有的类型是自定义类类型(MyClass)还是Framework(System.String)提供的类型。

有没有反思我可以将我的类类型与system.string或其他框架提供的类型区分开来?

6 个答案:

答案 0 :(得分: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类来检查公钥标记。这取决于你的需求。

答案 1 :(得分: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));

答案 2 :(得分:4)

您可以检查声明类型的程序集。

object.GetType().Assembly

答案 3 :(得分:1)

检查程序集是否属于CLR库:

myType.Module.ScopeName == "CommonLanguageRuntimeLibrary"

解释here

答案 4 :(得分:0)

并非所有框架类都在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不是框架类开头的命名空间)。

修改

此外,除了上述测试之外,验证从全局程序集缓存加载类型也没有问题:

typeof(MyType).Assembly.GlobalAssemblyCache

答案 5 :(得分:0)

我的解决方案,如果有帮助的话:

bin/spark-shell --packages com.datastax.spark:spark-cassandra-connector_2.11:2.5.1 \
   --conf spark.sql.extensions=com.datastax.spark.connector.CassandraSparkExtensions