如何确定一个对象类型是否为内置系统类型

47
我正在编写一个简单的 List<t> 到 CSV 转换器。我的转换器检查 List 中的所有 t,并获取所有公共属性并将其放入 CSV 中。
当您使用具有少量属性的简单类时,我的代码效果很好(按预期工作)。
我希望让 List<t> 到 CSV 转换器也能接受 System 类型,例如 String 和 Integer。对于这些系统类型,我不想获取它们的公共属性(例如 Length、Chars 等)。因此,我想检查对象是否为 System 类型。通过 System 类型,我指的是内置的 .Net 类型之一,例如 string、int32、double 等。
使用 GetType(),我可以找出以下信息:
string myName = "Joe Doe";

bool isPrimitive = myName.GetType().IsPrimitive; // False
bool isSealed = myName.GetType().IsSealed; // True 
// From memory all of the System types are sealed.
bool isValueType = myName.GetType().IsValueType; // False

// LinqPad users: isPrimitive.Dump();isSealed.Dump();isValueType.Dump();

如何判断变量myName是一个内置的System类型?(假设我们不知道它是否为字符串)


1
你认为什么是系统类型,什么不是? - BoltClock
我不知道正确的术语,但我认为stringint32是系统类型,而Employee显然不是。基本上,任何不是由编译器创建的类型。 - Jeremy
5
你是只在寻找编译器内置的类型吗?还是想要 System 命名空间中的所有类型? - Gabe
@Gabe 哦,我明白你的意思了,只需将根命名空间与“System”进行比较? - Jeremy
8个回答

60

以下是其中几种可能性:

  • myName.GetType().Namespace == "System"
  • myName.GetType().Namespace.StartsWith("System")
  • myName.GetType().Module.ScopeName == "CommonLanguageRuntimeLibrary"

4
@JeremyChild System.Security.Cryptography.Pkcs.SignedCms类型的Module.ScopeName等于System.Security.dll,因此不仅应检查一个"CommonLanguageRuntimeLibrary"。我已添加检查,如下所示:moduleScope == "CommonLanguageRuntimeLibrary" || moduleScope.StartsWith("System") || sourceType.Namespace.StartsWith("System") || sourceType.Namespace.StartsWith("Microsoft") - oleksa
1
模块作用域名称测试似乎无法在.NET Core中工作。 typeof(string).Module.ScopeNametypeof(List <string>).Module.ScopeName都返回“System.Private.CoreLib.dll”。 - Maxime Rossini

48

myName.GetType().Namespace 这段代码将返回系统内置类型的命名空间System。


12
这回答了问题,但并没有解决问题。你如何知道System命名空间中的所有值类型都可以忽略其属性?你真的想对System.ArgIteratorSystem.Nullable<Employee>这样做吗? - Raymond Chen
基于命名空间的方法可能会导致冲突。有关详细信息,请参见以下评论:https://dev59.com/A2025IYBdhLWcg3wkG17#44682414 - Makeman
2
@NetMage,程序员可以在不同的程序集中使用自定义类型扩展系统命名空间。如果我们使用字符串命名空间,可能会得到不正确的结果,因为这些类型不是语言内置的。 (new System.CustomType().GetType().Namespace)==“System” - Makeman
@Makeman 不错,虽然我不会称那为碰撞。 - NetMage
@NetMage 对我来说,这似乎是可能的命名冲突。 - Makeman

15

如果您无法准确定义“内置系统类型”是什么,那么您很可能不会知道在给出的任何答案中都包含哪些类型。更有可能的是,您只想要一个不希望使用它的类型列表。编写一个“IsSimpleType”方法,只对各种类型进行检查。

您可能正在寻找的另一件事是原始类型。如果是这样,请看:

Type.IsPrimitive (http://msdn.microsoft.com/en-us/library/system.type.isprimitive.aspx)

原始类型包括Boolean、Byte、SByte、Int16、UInt16、Int32、 UInt32、Int64、UInt64、IntPtr、UIntPtr、Char、Double和Single。

这不包括字符串,但您可以手动添加...

另请参阅如何测试类型是否为原始类型


10

基于命名空间的方法可能会导致冲突。

还有一种可靠且简单的方式:

static bool IsSystemType(this Type type) => type.Assembly == typeof(object).Assembly;

或者更优化一点,缓存系统装配件:

static readonly Assembly SystemAssembly = typeof(object).Assembly;

static bool IsSystemType(this Type type) => type.Assembly == SystemAssembly;

尝试使用 System.Windows.Point - NetMage
"System.Windows.Point"不是像object、int、string、DateTime、TimeSpan等语言内置的系统类型。看起来这个问题是关于内置类型的。 - Makeman
我不同意所谓的内置功能:为什么Action<,,,,,,,>(8个参数)应该与Action<,,,,,,,,>(9个参数)不同?或者为什么System.Collections.HashtableSystem.Collections.ArrayList是内置的,但System.Collections.BitArray不是?或者System.IO.FileAttributes不是内置的,但System.IO.FileOptions是内置的呢? - NetMage
如果我们考虑经典的.NET Framework 4.7.2,所有这些类型都包含在mscorelib程序集中,除了来自System.Core的Action<,,,,,,,,>(9个参数)。因此,您可以根据自己的想法自定义内置程序集列表。我只想说,比较程序集比比较字符串命名空间更安全。 - Makeman

6

我认为这是最好的可能性:

private static bool IsBulitinType(Type type)
{
    return (type == typeof(object) || Type.GetTypeCode(type) != TypeCode.Object);
}

1
只是一个警告:如果对象实现了IConvertible接口并返回其他类型,则Type.GetTypeCode()可能会返回非对象代码:http://msdn.microsoft.com/en-us/library/system.typecode.aspx - James Wilkins
如果一个对象属性是字符串,在这里它会返回true。如果意图是确定类型是否为自定义类型,则此方法不适用。 - rswank
1
System.TimeSpan 丢失。 - T-moty

3

我正在反射地构建某些东西,并发现IsSecurityCritical属性似乎适用于此目的; 但是,这仅是因为对于我的程序集而言,信任级别不足以翻转该位。

有点好笑。谢天谢地,我找到了这个问题并会相应地进行调整。

注意:如果 .NetFramework > 4,则只存在IsSecurityCritical属性。

我可能会使用以下先前答案中的内容:

myName.GetType().Module.ScopeName == "CommonLanguageRuntimeLibrary"

但是,稍作修改;例如将其作为扩展方法应用于Type上,并使用const代替CommonLanguageRuntimeLibrary


你是否检查过CoreCLR以确保ScopeName保持不变? - Jeremy

0

我更喜欢

colType.FullName.StartsWith("System")

而不是

colType.Namespace.StartsWith("System")

因为 Namespace 可能为空。


0

鉴于现有答案的注意事项,我建议一个仅适用于Windows的解决方案:

public static class TypeExt {
    public static bool IsBuiltin(this Type aType) => new[] { "/dotnet/shared/microsoft", "/windows/microsoft.net" }.Any(p => aType.Assembly.CodeBase.ToLowerInvariant().Contains(p));
}

假定在其他支持的操作系统上也有类似的路径。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接