C# 如何确定System.Type是自定义类型还是框架类型?

C# 如何确定System.Type是自定义类型还是框架类型?,c#,reflection,types,C#,Reflection,Types,我想清楚地确定我拥有的类型是自定义类类型(MyClass)还是框架提供的类型(System.String) 反射中是否有任何方法可以将我的类类型与system.string或其他框架提供的类型区分开来?您可以检查声明类型的程序集 object.GetType().Assembly 如果您只想区分MyClass和string,则可以直接检查这些类型: Type typeToTest = GetTypeFromSomewhere(); if (typeToTest == typeof(MyCla

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


反射中是否有任何方法可以将我的类类型与system.string或其他框架提供的类型区分开来?

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

object.GetType().Assembly

如果您只想区分
MyClass
string
,则可以直接检查这些类型:

Type typeToTest = GetTypeFromSomewhere();

if (typeToTest == typeof(MyClass))
    MyClassAction();
else if (typeToTest == typeof(string))
    StringAction();
else
    NotMyClassOrString();
如果需要对给定类型是否为框架类型进行更一般的检查,则可以检查它是否属于
系统
命名空间:

// 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));

并非所有框架类都以系统名称空间开始(它们也可以是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

安全检查类型是否为程序集的一部分的唯一方法是检查程序集的完全限定名,其中包含其名称、版本、区域性和公钥(如果已签名)。所有.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); 
//根据需要添加更多.Net BCL名称
var systemNames=newhashset
{
“mscorlib,版本=4.0.0.0,区域性=中性,PublicKeyToken=b77a5c561934e089”,
System.Core,版本=4.0.0.0,区域性=中性,PublicKeyToken=b77a5c561934e089
};
var isSystemType=systemNames.Contains(objToTest.GetType().Assembly.FullName);
一个稍微不那么脆弱的解决方案是使用该类并跳过版本号/区域性检查。当然,这是假设公钥在不同版本之间不会更改

//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()));
//根据需要添加更多.Net BCL名称
var systemNames=新列表
{
新的AssemblyName(“mscorlib,版本=4.0.0.0,区域性=neutral,”+
“PublicKeyToken=b77a5c561934e089”),
新的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类来检查公钥令牌。这取决于您的需要。

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

myType.Module.ScopeName == "CommonLanguageRuntimeLibrary"

如前所述。

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

private static readonly string _RuntimeDirectory =
    System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory();
public static bool IsSystem(this Type type)
    => type.Assembly.Location.StartsWith(_RuntimeDirectory);

因此,接下来的问题是:如何知道程序集是.NET framework的一部分?如果名称空间被称为“SystemUtil”,那么它就不是真正的防弹的@托马斯:我在发帖后不久就意识到了这一点,但在我编辑之前就被叫走了。现在已修复。我非常确定您可以编写自己的程序集,并创建名称空间
系统。[something]
。。。我不太喜欢这样做,但我知道一些开源项目确实如此——例如,@Dan:这是非常正确的,尽管这也是一种非常糟糕的做法。我进行了编辑,包括对程序集的
PublicKeyToken
的检查,以确保它是真正的系统类型。当然,如果您只想检查它是否是核心系统类型,那么您可以只执行
if(typeToTest.Assembly==typeof(int.Assembly)
,但这将排除更广泛的
系统的成员。*
命名空间(例如,
XmlDocument
)。我想这真的取决于OP想要实现什么。就我所知,BCL只包含
系统。*
名称空间。
Microsoft.*
名称空间是BCL(有时称为FCL)的超集,不属于ECMA CLI标准@卢卡:说得很好。我要说的重要一点是不要依赖于从System开始的名称空间。正如其他解决方案所显示的那样,明白始终是最好的选择;这是一张“穷人”支票,我以为我会吐出来以防万一。