为什么我不能传递这个类的实例......
class Item<T> where T : Thing { }
...进入这个方法:
void DoSomething(Item<Thing> item);
由于我已将Item<T>
限制为Item<Thing>
,因此在将项目发送到DoSomething
之前进行投射应该是安全的 - 但为什么框架不会处理此问题?
答案 0 :(得分:2)
假设你有一个班级:
public class SomeOtherThing : Thing { }
Item<SomeOtherThing>
<\ n> <\ n> 它们不一样。
让我们暂时假设该项看起来像这样:
Item<Thing>
public class Item<T>
{
public T Value { get; set; }
}
可能会执行以下操作:
DoSomething
如果您将void DoSomething(Item<Thing> item)
{
item.Value = new Thing();
}
传递给Item<SomeOtherThing>
,那么您现在刚刚将DoSomething
分配给Thing
,,但值是{{1}类型的属性1}},您无法设置Value
对象。这将破坏类型系统。编译器知道这是一个选项。由于这一点(以及任何其他具有相同基本问题的操作),SomeOtherThing
无法转换为Thing
。
那么,你能做什么?
好吧,如果你控制Item<SomeOtherThing>
的定义,也许它也应该是通用的。
如果Item<Thing>
看起来像这样:
DoSomething
然后您可以使用DoSomething
来调用它,因为之前会导致问题的操作不再在void DoSomething<T>(Item<T> item)
where T : Thing
{ }
内有效。
答案 1 :(得分:1)
想象
class Derived : Thing {}
Item<Derived>
无法分配给Item<Thing>
。
答案 2 :(得分:1)
你需要在方法声明中更具体一些;
void DoSomething<T>(Item<T> item)
where T : Thing
{
// now your method knows that T must be of time Thing and you can use it
}
答案 3 :(得分:1)
您遇到的问题是您的方法特定于Item<Thing>
,Item<Something>
不是有效参数。 C#不支持泛型类协方差。你有几个选择。
“最简单”的做法是简单地使你的方法通用并为Thing添加一个约束。这将是第一个建议的方法。
void DoSomething<T>(Item<T> item) where T : Thing
{
}
这将授予您对Thing
所有成员的访问权限,同时仍然有一个可以满足所有子类的方法。
另一个具有更多限制的选项是将Item<Thing>
的非通用基础简化为Item
。 (在其中,无论您以前在哪里暴露T,都会暴露object
。请注意:IEnumerable<T>
:IEnumerable
。)
void DoSomething(Item item)
{
}
您的方法只是期望Item
,您可以使用它。但是如果你有一个特定的要求与Thing
一起使用,它会更加精致,你需要适当地进行投射,但是你也可能面临某人传递不是<的实例的可能性/ em>一个Item<T>
,其中T是一件事。
另一个选项是单独保留方法的签名并从类转换为接口,这允许您使用协方差。 (.NET 4.0中支持接口和委托类型的Co / contravariance。)
interface Item<out T>
{
T Get();
// void Set(T foo); // invalid
}
同样,这里的问题是1)你需要改变你的类型(显然),但是2)你只能在输出位置暴露T
。请注意,支持Get()
方法。 Set(T)
方法不是,因为T
是一个输入,这使得接口不具有协同有效性。 (想象一下,传递Item<Something>
,并且您的方法尝试使用Set
拨打SomeOtherThing
。两者都是Things
,但显然第二个不适合第一个。)所以如果您需要支持T
输出和输入,则无法使用此方法。