如何检查T类型是否适合unmanaged类型约束,以便可以在这样的上下文中使用它:class Foo<T> where T : unmanaged?我的第一个想法是typeof(T).IsUnmanaged或类似的东西,但这不是Type类的属性/字段

最佳答案

根据 unmanaged 约束文档:
unmanaged类型是不是引用类型的类型,并且在任何嵌套级别均不包含引用类型字段。

在有关unmanaged type constraint的C#语言设计文档中也提到了它:

为了满足此约束,类型必须是struct,并且该类型的所有字段都必须属于以下类别之一:

  • 具有类型sbytebyteshortushortintuintlongulongcharfloatdoubledecimalboolIntPtrUIntPtr
  • 是任何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;
        }
    }
    

    更多信息

    您可能会发现以下链接有用:
  • 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
  • 10-02 01:45