无法从程序集中的所有类型中获取 Span<Type>

Posted

技术标签:

【中文标题】无法从程序集中的所有类型中获取 Span<Type>【英文标题】:Unable to get a Span<Type> from all types in an assembly 【发布时间】:2021-01-04 14:20:05 【问题描述】:

我正在尝试获取程序集中的所有类型 (assembly.GetTypes()),并尝试从中获得一个跨度,而无需任何看起来像 assembly.GetTypes().AsSpan() 的堆分配。然而奇怪的是,这会引发以下错误:

System.ArrayTypeMismatchException: '试图以与数组不兼容的类型访问元素。'

这让我有点困惑,更让我困惑的是assembly.GetTypes().ToArray().AsSpan() 运行时没有任何问题,但这显然不是解决方案。

一个小提琴,它表明这可以在here找到。

【问题讨论】:

【参考方案1】:

assembly.GetTypes() 返回一个RuntimeType[],但它使用数组类型协方差将其伪装成Type[]。根据Span constructor 的文档,如果T(在本例中为Type)与运行时数组类型(在本例中为RuntimeType)不匹配,则会引发ArrayTypeMismatchException

另一方面,

assembly.GetTypes().ToArray() 返回一个实际的Type[]:它将根据声明的类型T(即Type)创建一个全新数组,因此您会得到一个真正的 Type[] 数组并且没有不匹配 -- TType 并且您将真正的 Type[] 传递给 Span 构造函数。

ReadOnlySpan&lt;T&gt; 没有这个约束,因为不可能将不兼容的Type 写入只读的RuntimeType[],所以你可以这样做:

new ReadOnlySpan<Type>(assembly.GetTypes());

【讨论】:

而且 RuntimeType 是不公开的,所以将其转换回不必复制数组是不可能的(只是想找到一个不涉及复制数组的解决方案) 我的意思是这绝对是有道理的,即使这确实有点让人头疼,因为无论我做什么,我都不能直接从这个数组创建一个跨度,对吧? 这样的感觉应该记录在AsSpan方法中。 @Twenty 我已经用可能对您有用的替代方法更新了我的答案。如果您不打算向跨度写入任何内容,那么您可以使用不会抛出的ReadOnlySpan @Jeff Oh 实际上比预期的要容易得多,幸运的是我没有修改数组,所以非常感谢!

以上是关于无法从程序集中的所有类型中获取 Span<Type>的主要内容,如果未能解决你的问题,请参考以下文章

Span<T> 和朋友不在 .NET Native UWP 应用程序中工作

无法从程序集中加载类型

为啥我无法从与设置文件相同的项目/程序集中为设置选择自定义类型?

在 Unity 中实现 Span<T>

如何从应用程序域中所有加载的程序集中获取所有静态类并使用反射调用静态方法

如何从 simplejdbctemplate 查询中获取字符串列表或类型 T?