C# 检查对象是否为 Span<T>
C# Checking if object is Span<T>
目前我正在 .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<>
IS an object,但在编译时,我遇到了警告和错误:CS0184 警告 "unmanaged" is never of the "object"
类型,而 CS0039 告诉我"System.Span<byte>" cannot be converted to "object" via a reference conversion, boxing conversion, unboxing conversion, wrapping conversion, or null type conversion
。至少,文档指出 Span<>
确实不是通常的 object
。
是否有任何其他方法(只有一个依赖项 Mono.Cecil
)来确定某些 object
(或另一条基础数据,由 IntPtr
引用,至少) 是 Span 派生的?
Span<T>
是一个 ref
(stack-only) 结构,这意味着它不能保存到 object
类型的变量中,因为它不能被装箱.
来自 Span<T>
docs(强调我的):
Span is a ref struct that is allocated on the stack rather than on the managed heap. Ref struct types have a number of restrictions to ensure that they cannot be promoted to the managed heap, including that they can't be boxed, they can't be assigned to variables of type Object [...]
所以当你有一个变量或参数 object obj
时,你知道 obj
永远不会是 Span<T>
,因为 obj
总是指向一个对象堆(例如,当您将整数存储在 obj
中时,它将自动装箱到堆对象中)。
但是它可能是一个Memory<T>
,它是Span<T>
.[=23=的非堆栈(普通结构)等价物]
好吧,我知道这实际上不太好,但我必须处理名称检查方法。由于 System.Span<T>
class 的半对象(无论什么)性质,我们不能将 Span
与任何对象进行比较,但我们可以使用 typeof(System.Span<byte>)
这样的比较。这只有在我们总是知道初步的情况下才有用,如何(即,用哪个 T
)Span
可以实例化,但这实际上不是我的情况。除了名称检查之外,似乎没有可靠的机制来区分 Span
。因此,检查类型名称似乎是唯一合适的方法。
使用 Mono.Cecil
,我使用 TypeReference
以下条件:
bool IsSpanType(TypeReference type) {
return type.FullName.StartsWith("System.Span`1");
}
如您所见,没有幸福的结局,但它工作得很好。而且我看不出有任何理由再执行任何偏执检查(例如检查 TypeReference
的此类属性,如 Scope
、ElementType
或其他)。
目前我正在 .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<>
IS an object,但在编译时,我遇到了警告和错误:CS0184 警告 "unmanaged" is never of the "object"
类型,而 CS0039 告诉我"System.Span<byte>" cannot be converted to "object" via a reference conversion, boxing conversion, unboxing conversion, wrapping conversion, or null type conversion
。至少,文档指出 Span<>
确实不是通常的 object
。
是否有任何其他方法(只有一个依赖项 Mono.Cecil
)来确定某些 object
(或另一条基础数据,由 IntPtr
引用,至少) 是 Span 派生的?
Span<T>
是一个 ref
(stack-only) 结构,这意味着它不能保存到 object
类型的变量中,因为它不能被装箱.
来自 Span<T>
docs(强调我的):
Span is a ref struct that is allocated on the stack rather than on the managed heap. Ref struct types have a number of restrictions to ensure that they cannot be promoted to the managed heap, including that they can't be boxed, they can't be assigned to variables of type Object [...]
所以当你有一个变量或参数 object obj
时,你知道 obj
永远不会是 Span<T>
,因为 obj
总是指向一个对象堆(例如,当您将整数存储在 obj
中时,它将自动装箱到堆对象中)。
但是它可能是一个Memory<T>
,它是Span<T>
.[=23=的非堆栈(普通结构)等价物]
好吧,我知道这实际上不太好,但我必须处理名称检查方法。由于 System.Span<T>
class 的半对象(无论什么)性质,我们不能将 Span
与任何对象进行比较,但我们可以使用 typeof(System.Span<byte>)
这样的比较。这只有在我们总是知道初步的情况下才有用,如何(即,用哪个 T
)Span
可以实例化,但这实际上不是我的情况。除了名称检查之外,似乎没有可靠的机制来区分 Span
。因此,检查类型名称似乎是唯一合适的方法。
使用 Mono.Cecil
,我使用 TypeReference
以下条件:
bool IsSpanType(TypeReference type) {
return type.FullName.StartsWith("System.Span`1");
}
如您所见,没有幸福的结局,但它工作得很好。而且我看不出有任何理由再执行任何偏执检查(例如检查 TypeReference
的此类属性,如 Scope
、ElementType
或其他)。