我得到的具体例外是:
无法将
类型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
声明了它)。这可能吗?
答案 0 :(得分:7)
界面差异仅适用于参考类型。排除值类型(例如整数,字节等,以及自定义结构)。例如,即使数组为IEnumerable<object>
,也不能将整数数组用作IEnumerable<int>
。
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
}
}
答案 1 :(得分:1)
使用泛型类型的一个限制方面是泛型类型在类型转换中不像传统类型那样灵活。 List<Object>
与List<String>
或任何其他对象类型的分配不兼容。
Linq中有转换辅助函数,例如.Cast<T>()
,它将逻辑上将每个元素从一个列表转换为T类型,以形成类型为List<T>
的新列表。尽管辅助函数很方便,但它并没有改变List<N>
与List<T>
不兼容的事实,即使N和T在某种程度上是类型兼容的。
本质上,泛型类型不是多态的。同一泛型类型的实例之间没有通用类型 - 没有类型可以声明一个可以容纳List<T>
的变量一个List<N>
。
如果您正在创建自己的通用类型,并且您确实希望有一些可用于携带泛型类型的所有表现形式的常见类型,则必须执行某些类型的体操以使其工作,并且您将限制你能做什么。您需要定义基类或接口类型,然后需要使您的泛型类型继承自基类或实现接口类型。使用此配置,您可以使用基类类型或接口类型声明变量,并可以将MyClass<N>
和MyClass<T>
分配给同一个变量,只访问基类中定义的成员(将使用当然对N或T型参数没有任何了解。)
协变类型参数(IMyInterface<out T>
)可能会让你成为那里的一部分,但协方差会严格限制你在该界面中可以做的事情 - 协变类型T只能用于函数结果,永远不能用于参数或可设置的属性。
IList<T>
未被声明为协变的简单事实不是意外或疏忽 - 它不能协变。要有用IList<T>
需要添加(T项)和删除(T项)等方法,当T是协变时,这些方法是禁止的。