C#.净协方差-又一次为了旧时代?
因此,我们有:C#.净协方差-又一次为了旧时代?,c#,.net,covariance,contravariance,C#,.net,Covariance,Contravariance,因此,我们有: public interface IWidget { int Id { get; set; } } public class Widget : IWidget { public int Id { get; set; } } public class WidgetProcessor { public static void ProcessWidgets1(IList<IWidget> widgets) { } public
public interface IWidget
{
int Id { get; set; }
}
public class Widget : IWidget
{
public int Id { get; set; }
}
public class WidgetProcessor
{
public static void ProcessWidgets1(IList<IWidget> widgets)
{ }
public static void ProcessWidgets2<T>(IList<T> widgets) where T : IWidget
{ }
}
公共接口IWidget
{
int Id{get;set;}
}
公共类小部件:IWidget
{
公共int Id{get;set;}
}
公共类WidgetProcessor
{
公共静态void ProcessWidgets1(IList小部件)
{ }
公共静态void ProcessWidgets2(IList小部件),其中T:IWidget
{ }
}
我明白为什么这不能编译:
WidgetProcessor.ProcessWidgets1(新列表())代码>
关于协方差的C#规则明智地说它不应该这样做,否则你可能会做出各种各样的调皮行为,正如在其他地方详细解释的那样
但是ProcessWidgets2:什么…?
该如何编译和运行:
WidgetProcessor.ProcessWidgets2(新列表())代码>
期待着消除我的无知,但我看不出ProcessWidgets1和ProcessWidgets2(实际上)有什么不同。ProcessWidgets2
是一种通用方法。当您使用new List()
调用它时,编译器推断类型T
是Widget
,它与约束匹配,并调用它,因为List
实现了IList
如果将其分解为多个调用,则最容易将其视为:
IList<Widget> temp = new List<Widget>();
WidgetProcessor.ProcessWidgets2<Widget>(temp); // Widget is an IWidget, so this matches constraints
IList temp=new List();
WidgetProcessor.ProcessWidgets2(临时);//小部件是一个IWidget,因此它匹配约束
这里没有变化,因为List
直接实现了IList
,并且您使用编译器推断的特定类型进行调用。在第一个示例中,您可以执行代码:
widgets.Add(new SomeOtherWidget());
如果小部件
实际上被允许成为列表
,那么您应该将其他小部件
放入小部件
对象列表中。这会很糟糕,因为当你取出一个对象时,它可能根本不是一个小部件
对于第二个示例,widgets.Add(newsomeotherwidget())代码>无法编译SomeOtherWidget
将不是t
类型。您将只允许使用类型为T
的对象调用列表中的Add
,而不是任何旧的IWidget
对象,因此它能够维护类型安全。通用推理!!谢谢-一旦推断参数明确包含在调用中,它就会变得清晰。