无法强制转换MyType<;T>;到MyType<;对象>;

本文关键字:gt MyType lt 对象 转换 | 更新日期: 2023-09-27 18:25:05

我得到的特定异常是:

无法将NbtByte类型的对象强制转换为INbtTag<System.Object> 类型

在线:

tag = (INbtTag<object>)new NbtByte(stream);

其中tag声明为:

INbtTag<object> tag;

NbtByte定义为:

public class NbtByte : INbtTag<byte>

其中IBtTag为:

public interface INbtTag<out T>

我想通过将它声明为out T,我就可以做这样的事情。

基本上,我想要一本IbtTag<T>s、的字典

var dict = new Dictionary<string, INbtTag<object>>();

但是其中T是不同类型的(因此我用object声明它)。这可能吗?

无法强制转换MyType<;T>;到MyType<;对象>;

接口差异仅适用于引用类型。值类型(如int、字节等,以及自定义结构)被排除在外。例如,即使数组是IEnumerable<int>,也不能将整数数组用作IEnumerable<object>

IEnumerable<object> objs = new int[] { 1, 2, 3 }; // illegal
IEnumerable<object> objs = new string[] { "a", "b", "c" }; // legal

为了解决字典的问题,您可以选择定义一个非通用接口。(如果您的通用接口可能将成员公开为类型T,那么非通用接口只会公开object。)

假设你有

interface INbtTag { } // non-generic interface 
interface INbtTag<out T> : INbtTag { } // covariant generic interface

然后你就可以用你的字典作为Dictionary<string, INbtTag>

缺点是,当您实现接口时,必须同时实现这通常意味着隐式实现泛型版本,而显式实现非泛型版本。例如:

interface INbtTag
{
    object GetValue(); 
}
interface INbtTag<out T> : INbtTag
{
    T GetValue();
}
class NbtByte : INbtTag<byte>
{
    byte value;
    public byte GetValue() // implicit implementation of generic interface
    {
        return value;
    }
    object INbtTag.GetValue() // explicit implementation of non-generic interface
    {
        return this.GetValue(); // delegates to method above
    }
}

使用泛型类型的一个限制方面是泛型类型在类型转换方面不如传统类型灵活。List<Object>List<String>或任何其他对象类型的赋值不兼容。

Linq中有转换辅助函数,如.Cast<T>(),它将从一个列表中的每个元素逻辑地强制转换为T类型,以形成类型为List<T>的新列表。虽然helper函数很方便,但它并没有改变List<N>List<T>不类型兼容的事实,即使N和t在某种程度上是类型兼容的。

从本质上讲,泛型类型不是多态的同一泛型类型的实例之间没有通用类型——没有一种类型可以用来声明可以容纳List<T>List<N>的变量。

如果你正在创建自己的泛型类型,并且你确实希望有一些通用类型可以用来承载泛型类型的所有表现,那么你必须执行一些类型体操才能使其发挥作用,你所能做的将受到限制。你需要定义一个基类或接口类型,然后需要使泛型类型从基类继承或实现接口类型。使用此配置,您可以用基类类型或接口类型声明一个变量,并可以将MyClass<N>MyClass<T>分配给同一变量,只访问基类中定义的成员(当然,这些成员对N或T类型参数一无所知)。

协变类型参数(IMyInterface<out T>)可能会让你实现这一目标,但协变对你在该接口中的操作施加了严格的限制——协变类型T只能用于函数结果,而不能用于参数或可设置属性。

IList<T>没有被宣布为协变的简单事实不是偶然或疏忽——它不可能是协变的。为了有用,IList<T>需要Add(T项)和Remove(T项)等方法,当T是协变时,这些方法是被禁止的。