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
对象,因此它能够维护类型安全。

通用推理!!谢谢-一旦推断参数明确包含在调用中,它就会变得清晰。