如何检查T
类型是否适合unmanaged
类型约束,以便可以在这样的上下文中使用它:class Foo<T> where T : unmanaged
?我的第一个想法是typeof(T).IsUnmanaged
或类似的东西,但这不是Type
类的属性/字段
最佳答案
根据 unmanaged
约束文档:unmanaged
类型是不是引用类型的类型,并且在任何嵌套级别均不包含引用类型字段。
在有关unmanaged type constraint的C#语言设计文档中也提到了它:
为了满足此约束,类型必须是struct,并且该类型的所有字段都必须属于以下类别之一:
sbyte
,byte
,short
,ushort
,int
,uint
,long
,ulong
,char
,float
,double
,decimal
,bool
,IntPtr
或UIntPtr
。 enum
类型。 unmanaged
约束的用户定义结构。 注意事项
通常,调用
MakeGenericType
是验证CRL强制执行的通用类型约束的最可靠解决方案。通常,尝试自己实现验证不是一个好主意,因为您可能需要考虑很多规则,并且总是有可能遗漏其中一些规则。但是请注意,至少在编写此答案时,它对于unmanaged
约束不是很好。.NET Core有一个
RuntimeHelpers.IsReferenceOrContainsReferences
,但在编写此答案时,.NET Framework没有此功能。我应该提到,即使使用IsReferenceOrContainsReferences
也不完全可靠。例如,参见the issue which I posted here,它涉及两个没有任何引用类型的结构,但其中一个被评估为托管,其中一个为非托管(可能是编译器错误)。
无论如何,现在根据您的喜好和要求,使用以下解决方案之一来检测哪种类型可以满足
unmanaged
通用类型约束。选项1-使用MakeGenericType
作为一种选择,要检查类型是否可以满足
unmanaged
约束,可以使用以下IsUnmanaged
扩展方法。using System;
using System.Reflection;
public static class UnmanagedTypeExtensions
{
class U<T> where T : unmanaged { }
public static bool IsUnManaged(this Type t)
{
try { typeof(U<>).MakeGenericType(t); return true; }
catch (Exception){ return false; }
}
}
选项2-编写自己的方法来检查记录的规则
作为另一种选择,您可以编写方法来检查记录的规则中是否存在
unmanaged
约束。以下代码具有更多规则,而不是其他答案,以便能够处理诸如int?
或(int,int)
的情况:using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
public static class UnmanagedTypeExtensions
{
private static Dictionary<Type, bool> cachedTypes =
new Dictionary<Type, bool>();
public static bool IsUnManaged(this Type t)
{
var result = false;
if (cachedTypes.ContainsKey(t))
return cachedTypes[t];
else if (t.IsPrimitive || t.IsPointer || t.IsEnum)
result = true;
else if (t.IsGenericType || !t.IsValueType)
result = false;
else
result = t.GetFields(BindingFlags.Public |
BindingFlags.NonPublic | BindingFlags.Instance)
.All(x => x.FieldType.IsUnManaged());
cachedTypes.Add(t, result);
return result;
}
}
更多信息
您可能会发现以下链接有用: