【问题标题】:C# Checking if object is Span<T>C# 检查对象是否为 Span<T>
【发布时间】:2021-03-20 00:04:22
【问题描述】:

目前我正在 .NET Core 3.1 下编写 C# 代码以检查当前类型(我使用 Mono.Cecil,但 System.Reflection 可能更适合)是否为 Span 类型。找到有关如何检查类型是否为generic 的信息后,我为此类检查编写了一些虚拟代码:

        unsafe
        {
            IntPtr unmanagedHandle = Marshal.AllocHGlobal(16);
            Span<byte> unmanaged = new Span<byte>(unmanagedHandle.ToPointer(), 16);
            if (unmanaged is object)
                if ((unmanaged as object).GetType().GetGenericTypeDefinition() == typeof(Span<>))
                    Console.WriteLine("Span!");
            Marshal.FreeHGlobal(unmanagedHandle);
        }

尽管官方 MSDN 文档说 Span&lt;&gt; IS an object,但在编译时,我遇到了警告和错误:CS0184 警告 "unmanaged" is never of the "object" 类型,而 CS0039 告诉 "System.Span&lt;byte&gt;" cannot be converted to "object" via a reference conversion, boxing conversion, unboxing conversion, wrapping conversion, or null type conversion。至少,文档指出Span&lt;&gt; 不是通常的object

是否有任何其他方法(只有一个依赖项Mono.Cecil)来确定某些object(或至少由IntPtr 引用的另一条基础数据)是否是Span 派生的?

【问题讨论】:

  • 你可以试试as 的大小写吗?喜欢:if (unmanaged as Span != null)
  • 您永远不会遇到这样一种情况,即对未知类型的引用实际上是 Span&lt;&gt;,正如您所发现的那样。因此,简化代码的简单方法是回答 false
  • @Jonathan,使用“as”和Span,以任何形式,都会带来相同的 CS0039 错误
  • @Damien_The_Unbeliever,除非您需要枚举您在代码中遇到的所有类型 - 对于任何涉及反射的任务(如程序集混淆或保护)

标签: c# .net .net-core clr cil


【解决方案1】:

Span&lt;T&gt; 是一个ref(仅堆栈)结构,这意味着它不能保存到object 类型的变量中,因为它不能被装箱。

来自Span&lt;T&gt; docs(强调我的):

Span 是一个 ref struct,它分配在堆栈上而不是托管堆上。 Ref struct 类型有许多限制,以确保它们不能被提升到托管堆,包括 不能装箱,不能分配给 Object 类型的变量 [.. .]

所以当你有一个变量或参数object obj,你知道obj永远不会是一个Span&lt;T&gt;,因为obj总是指向堆上的一个对象(例如当你将一个整数存储在obj,会自动装箱成堆对象)。

但是它可能是Memory&lt;T&gt;,它是Span&lt;T&gt; 的非仅堆栈(普通结构)等价物。

【讨论】:

    【解决方案2】:

    好吧,我知道这实际上并不好,但我必须处理名称检查方法。由于System.Span&lt;T&gt; 类的半对象(无论)性质,我们无法将Span 与任何对象进行比较,但我们可以使用typeof(System.Span&lt;byte&gt;) 之类的比较。这只有在我们总是知道初步的情况下才有用,如何(即,与TSpan 可以实例化,但实际上这不是我的情况。除了名称检查之外,似乎没有可靠的机制来区分Span。因此,检查类型名称似乎是唯一合适的方法。

    使用Mono.Cecil,我将TypeReference用于以下条件:

    bool IsSpanType(TypeReference type) {
        return type.FullName.StartsWith("System.Span`1");
    }
    

    如您所见,没有快乐的结局,但它工作得很好。而且我看不出有任何理由进行更多的偏执检查(例如检查TypeReference 的此类属性,例如ScopeElementType 或其他任何东西)。

    【讨论】:

    • 您能否澄清一下,您是要测试某个对象实例是否属于Span&lt;...&gt; 类型,还是要测试一个类型为Type/TypeReference 的对象实例是否代表@987654336 @类型?
    • @thehennyy,仅限TypeReferences
    • type.IsGenericType &amp;&amp; typeof(Span&lt;&gt;).Equals(type.GetGenericTypeDefinition()) 有什么问题?您的问题表明您可以比较 System.Type 的实例。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-10-16
    • 1970-01-01
    • 2010-12-23
    • 1970-01-01
    • 2010-11-10
    • 1970-01-01
    • 2017-05-18
    相关资源
    最近更新 更多