如何检查类型 T
适合 unmanaged
类型约束,这样它就可以在这样的上下文中使用:class Foo<T> where T : unmanaged
?我的第一个想法是 typeof(T).IsUnmanaged
或类似的东西,但这不是 Type
的属性/字段类
最佳答案
根据 unmanaged
约束文档:
非托管
类型不是引用类型,并且在任何嵌套级别都不包含引用类型字段。
在 C# 语言设计文档中也提到了 unmanaged type constraint :
为了满足此约束,类型必须是结构并且该类型的所有字段必须属于以下类别之一:
- 具有类型
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
扩展方法。
C# 7.3: It is supposed to be more reliable, but I should say, it's not. It seems for
unmanaged
constraint, CLR is not respecting the constraint and it's just a C# compiler feature. So at least for now, I recommend using the second option.
C# 8.0: Works as expected in C# 8.0
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;
}
}
更多信息
您可能会发现以下链接很有用:
- Docs - Unmanaged constraint
- GitHub - C# 7.3 language design documents - Unmanaged type constraint
- A blog post by Sergey Teplyakov about Dissecting new generic constraints in C# 7.3
- A blog post by Maarten Balliauw about Unmanaged, delegate and enum type constraints
- GitHub Issue - Please clarify the implementation details of unmanaged generic constraints
- GitHub - Proposal: Unmanaged constructed types #1504
关于c# - 如何检查类型是否符合 C# 中的非托管约束?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53968920/