我如何检查类型T
是否适合unmanaged
类型约束,以便可以在诸如class Foo<T> where T : unmanaged
这样的上下文中使用它?我的第一个想法是typeof(T).IsUnmanaged
或类似的东西,但这不是Type
类的属性/字段
答案 0 :(得分:4)
根据unmanaged
约束文档:
unmanaged
类型是不是引用类型的类型,并且在任何嵌套级别均不包含引用类型字段。
C#语言设计文档中也提到了unmanaged type constraint:
为了满足此约束,类型必须是struct,并且该类型的所有字段都必须属于以下类别之一:
sbyte
,byte
,short
,ushort
,int
,uint
,long
,ulong
,char
,float
,double
,decimal
,bool
,IntPtr
或UIntPtr
。 / em> enum
类型。 unmanaged
约束。 注意事项
通常,调用MakeGenericType
是验证CRL强制执行的泛型类型约束的最可靠解决方案。通常,尝试自己实施验证不是一个好主意,因为您可能需要考虑很多规则,并且总是有可能遗漏其中一些规则。但是请注意,至少在编写此答案时,它不适用于unmanaged
约束。
.NET Core有一个RuntimeHelpers.IsReferenceOrContainsReferences
,但在编写此答案时,.NET Framework没有此功能。我应该提到,即使使用IsReferenceOrContainsReferences
也不完全可靠。
例如,关于the issue which I posted here的两个结构没有任何引用类型,但其中一个被评估为托管,其中一个为非托管(可能是编译器错误)。
无论如何,暂时根据您的喜好和要求,使用以下解决方案之一来检测哪种类型可以满足unmanaged
通用类型约束。
选项1-使用MakeGenericType
作为一种选择,要检查类型是否满足unmanaged
约束,可以使用以下IsUnmanaged
扩展方法'。
注意: 本来应该更可靠,但我应该说不是。对于
unmanaged
约束,CLR似乎没有遵守 约束,它只是C#编译器功能。所以至少 现在,我建议使用第二个选项。
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;
}
}
更多信息
您可能会发现以下链接有用:
答案 1 :(得分:3)
我不确定是否已经存在类似的东西,但是您可以实现类似于以下内容的扩展方法:
public static bool IsUnmanaged(this Type type)
{
// primitive, pointer or enum -> true
if (type.IsPrimitive || type.IsPointer || type.IsEnum)
return true;
// not a struct -> false
if (!type.IsValueType)
return false;
// otherwise check recursively
return type
.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
.All(f => IsUnmanaged(f.FieldType));
}
(更新)为了完整起见,由于具有许多嵌套成员的结构的递归速度较慢,因此可以通过缓存结果来使函数更快:
private static readonly ConcurrentDictionary<Type, bool> _memoized =
new ConcurrentDictionary<Type, bool>();
public static bool IsUnmanaged(this Type type)
{
bool answer;
// check if we already know the answer
if (!_memoized.TryGetValue(type, out answer))
{
if (!type.IsValueType)
{
// not a struct -> false
answer = false;
}
else if (type.IsPrimitive || type.IsPointer || type.IsEnum)
{
// primitive, pointer or enum -> true
answer = true;
}
else
{
// otherwise check recursively
answer = type
.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
.All(f => IsUnmanaged(f.FieldType));
}
_memoized[type] = answer;
}
return answer;
}