3

所以我们有这个:

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
    { }
}

我明白为什么这不会编译: WidgetProcessor.ProcessWidgets1(new List<Widget>()); 围绕协方差的 C# 规则明智地说它不应该,或者你可能会遇到各种顽皮,正如在其他地方详细解释的那样。

但是 ProcessWidgets2:什么...?
它是如何编译和运行的: WidgetProcessor.ProcessWidgets2(new List<Widget>());

期待消除我的无知,但我看不出 ProcessWidgets1 和 ProcessWidgets2 (实际上)有何不同。

4

2 回答 2

5

ProcessWidgets2<T>是一种通用方法。当你用 调用它时new List<Widget>(),编译器推断类型TWidget,它与约束匹配,并调用它,因为List<T>implements IList<T>

将其视为分解为多个调用可能最容易:

IList<Widget> temp = new List<Widget>();
WidgetProcessor.ProcessWidgets2<Widget>(temp); // Widget is an IWidget, so this matches constraints

这里没有变化,因为List<T>直接 implements IList<T>,并且您使用编译器推断的特定类型进行调用。

于 2013-03-21T15:55:31.217 回答
0

对于第一个示例,您可以执行代码:

widgets.Add(new SomeOtherWidget());

如果widgets实际上被允许成为 aList<Widget>那么您会将 aSomeOtherWidget放入对象列表中Widget。那会很糟糕,因为当你拿出一个对象时,它可能根本就不是一个Widget

对于第二个示例,widgets.Add(new SomeOtherWidget());将无法编译。 SomeOtherWidget不会是 type T。您将只被允许使用类型的对象而不是任何旧对象来调用Add列表,因此它能够保持类型安全。TIWidget

于 2013-03-21T16:11:29.347 回答