简体   繁体   English

如何检查类型是否符合 C# 中的非托管约束?

[英]How do I check if a type fits the unmanaged constraint in C#?

How do I check if a type T fits the unmanaged type constraint, such that it could be used in a context like this: class Foo<T> where T : unmanaged ?我如何检查类型T是否符合unmanaged类型约束,以便它可以在这样的上下文中使用: class Foo<T> where T : unmanaged My first idea was typeof(T).IsUnmanaged or something similar, but that isn't a property/field of the Type class我的第一个想法是typeof(T).IsUnmanaged或类似的东西,但这不是Type类的属性/字段

According to unmanaged constraint documentations:根据unmanaged约束文档:

An unmanaged type is a type that is not a reference type and doesn't contain reference type fields at any level of nesting. unmanaged类型是一种不是引用类型并且不包含任何嵌套级别的引用类型字段的类型。

Also it's mentioned in C# language design documentations about unmanaged type constraint :在 C# 语言设计文档中还提到了有关非托管类型约束的内容

In order to satisfy this constraint a type must be a struct and all the fields of the type must fall into one of the following categories:为了满足此约束,类型必须是结构,并且该类型的所有字段必须属于以下类别之一:

  • Have the type sbyte , byte , short , ushort , int , uint , long , ulong , char , float , double , decimal , bool , IntPtr or UIntPtr .具有sbytebyteshortushortintuintlongulongcharfloatdoubledecimalboolIntPtrUIntPtr
  • Be any enum type.是任何enum类型。
  • Be a pointer type.是一个指针类型。
  • Be a user defined struct that satisfies the unmanaged constraint.是满足unmanaged约束的用户定义结构。

Considerations注意事项

Usually calling MakeGenericType is the most reliable solution for validating generic type constraints which are enforced by CRL.通常调用MakeGenericType是验证由 CRL 强制执行的泛型类型约束的最可靠的解决方案。 Usually trying to implement validation by yourself is not a good idea because there may be a lot of rules which you should consider and there is always a chance for missing some of them.通常尝试自己实现验证不是一个好主意,因为您可能需要考虑很多规则,并且总是有可能遗漏其中的一些。 But be informed, at least at time of writing this answer, it's not working well for unmanaged constraint.但是请注意,至少在撰写此答案时,它不适用于unmanaged约束。

.NET Core have a RuntimeHelpers.IsReferenceOrContainsReferences but at the time of writing this answer, .NET Framework doesn't have such function. .NET Core 有一个RuntimeHelpers.IsReferenceOrContainsReferences但在撰写此答案时,.NET Framework 没有这样的功能。 I should mention that even using IsReferenceOrContainsReferences is not completely reliable for this task.我应该提到,即使使用IsReferenceOrContainsReferences也不能完全可靠地完成这项任务。

For example see the issue which I posted here about two structure which doesn't have any reference type but one of them evaluated as managed, one of them unmanaged (maybe a compiler bug).例如,请参阅我在此处发布的关于两个结构的问题,它们没有任何引用类型,但其中一个被评估为托管,其中一个被评估为非托管(可能是编译器错误)。

Anyway, for now depending to your preference and requirements, use one of the following solutions to detect which type can satisfy unmanaged generic type constraint.无论如何,现在根据您的偏好和要求,使用以下解决方案之一来检测哪种类型可以满足unmanaged泛型类型约束。

Option 1 - Using MakeGenericType选项 1 - 使用 MakeGenericType

As an option, to check if the type can satisfy the unmanaged constraint, you can use the following IsUnmanaged extension method'.作为一种选择,要检查类型是否满足unmanaged约束,您可以使用以下IsUnmanaged扩展方法'。

C# 7.3 : It is supposed to be more reliable, but I should say, it's not. C# 7.3 :它应该更可靠,但我应该说,它不是。 It seems for unmanaged constraint, CLR is not respecting the constraint and it's just a C# compiler feature.似乎对于unmanaged约束,CLR 不尊重约束,它只是 C# 编译器功能。 So at least for now, I recommend using the second option.所以至少现在,我建议使用第二个选项。

C# 8.0 : Works as expected in C# 8.0 C# 8.0 :在 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; }
    }
}

Option 2 - Writing your own method checking the documented rules选项 2 - 编写自己的方法检查记录的规则

As another option, you can write your method checking documented rules for unmanaged constraint.作为另一种选择,您可以编写检查unmanaged约束的记录规则的方法。 The following code has more rules rather than other answer to be able to handle cases like int?下面的代码有更多的规则而不是其他答案来处理像int? or (int,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;
    }
}

More Information更多信息

You may find the following links useful:您可能会发现以下链接很有用:

I am not sure if something like this already exists, but you could implement your own extension method similar to:我不确定这样的东西是否已经存在,但您可以实现自己的扩展方法,类似于:

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));
}

(update) For completeness, since recursion will be slow for structs with many nested members, the function can be made faster by caching the results: (更新)为了完整起见,由于具有许多嵌套成员的结构的递归会很慢,因此可以通过缓存结果使函数更快:

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;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 我的 SQL 服务器上有一个检查约束,如何在 c# 中设置检查约束的验证? - I have a check constraint on my SQL server, how do i set a validation for the Check Constraint in c#? 如何将非托管IntPtr类型转换为ac#string? - How can I convert an unmanaged IntPtr type to a c# string? 如何检查C#泛型类型是否为集合(IEnumerable)? - How do I check if a C# generic type is a collection (IEnumerable)? 如何将 `where T : U` 泛型类型参数约束从 C# 转换为 F#? - How do I translate a `where T : U` generic type parameter constraint from C# to F#? 如何约束通用类型参数以仅接受C#中的可为空的值类型? - How do I constraint a generic type parameter to only accept nullable value types in C#? 通用类型约束:如何创建 C# 文档中描述的 class 的实例 - Generic type constraint: How do I create an instance of the class described in this C# documentation 如何从C#ASP.NET网页调用非托管C / C ++代码 - How do I call unmanaged C/C++ code from a C# ASP.NET webpage 如何将多态性与泛型类型一起使用,该泛型类型的类型参数是 C# 中类型参数约束的子类型? - How do I use polymorphism with a generic type who's type argument is a child of the type parameter constraint in c#? 如何在 C# 中将非托管类型转换为托管类型? - How to convert unmanaged type to managed type in C#? 如何添加对C#项目调用的非托管C ++项目的引用? - How do I add a reference to an unmanaged C++ project called by a C# project?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM