当结构是在 C# 中转换的通用对象的协变类型时,结构无法转换为对象的任何解决方法?

Posted

技术标签:

【中文标题】当结构是在 C# 中转换的通用对象的协变类型时,结构无法转换为对象的任何解决方法?【英文标题】:Any workarounds for structs failing to cast to object when the struct is the covariant type of a generic object being being casted in C#? 【发布时间】:2021-12-13 20:13:44 【问题描述】:

假设我使用协变类型参数 (struct) 实例化一个泛型类,然后我将新创建的对象转换为自身,并使用类型参数 object 代替 struct,转换将失败尽管差异应该允许。

例子:

public class Succeeds 
public struct Fails 

var castSucceeds = (IEnumerable<object>)Enumerable.Empty<Succeeds>();
var castFails = (IEnumerable<object>)Enumerable.Empty<Fails>();

正如您从上面看到的那样,由于IEnumerable&lt;T&gt; 的泛型类型是协变的,所以这个转换有效,但是当尝试使用struct 而不是class 时它会失败。我怀疑失败与将结构转换为对象时需要装箱有关。

有什么办法可以解决这个问题还是我看错了?

【问题讨论】:

正如文档 (docs.microsoft.com/en-us/dotnet/standard/generics/…) 所说:方差仅适用于引用类型;如果为变体类型参数指定值类型,则该类型参数对于生成的构造类型是不变的。 Variance 不适用于明显的原因:未装箱的值类型和类具有完全不同的布局。未装箱的值类型实际上并没有实现接口,只有装箱的版本才实现。对泛型进行了特殊优化以避免装箱,但在内部它最终成为直接方法调用 【参考方案1】:

根据Microsoft:

方差仅适用于引用类型;如果您指定值类型 对于变体类型参数,该类型参数对于 生成的构造类型。

尝试进行手动投射:

var castFails = Enumerable.Empty<Fails>().Cast<object>();

【讨论】:

谢谢,当我试图找出哪里出错时,我肯定错过了! 手动转换示例对我不起作用,因为我实际上并没有处理IEnumerable

以上是关于当结构是在 C# 中转换的通用对象的协变类型时,结构无法转换为对象的任何解决方法?的主要内容,如果未能解决你的问题,请参考以下文章

JAVA中的协变与逆变

(56)C#里的协变(covariant)和逆变(contravariant)

通用优先级队列中的协变和逆变类型

(56)C#里的协变(covariant)和逆变(contravariant)

为啥 C# (4.0) 不允许泛型类类型中的协变和逆变?

C#中的协变与逆变