Question

So we have this:

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

I get why this wouldn't compile: WidgetProcessor.ProcessWidgets1(new List<Widget>()); The C# rules around covariance wisely say it shouldn't, or you could get up to all sorts of naughtiness, as explained at length elsewhere.

But ProcessWidgets2: what the...?
How is it that this does compile and run: WidgetProcessor.ProcessWidgets2(new List<Widget>());

Look forward to having my ignorance removed, but I can't see how ProcessWidgets1 and ProcessWidgets2 are (effectively) any different.

Was it helpful?

Solution

ProcessWidgets2<T> is a generic method. When you call it with new List<Widget>(), the compiler infers that the type T is Widget, which matches the constraints, and calls it, since List<T> implements IList<T>.

It's potentially easiest to look at it as if it was broken up into multiple calls:

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

There is no variance in play here, since List<T> directly implements IList<T>, and you're calling with a specific type that's inferred by the compiler.

OTHER TIPS

With the first example you could execute the code:

widgets.Add(new SomeOtherWidget());

If widgets were actually allowed to be a List<Widget> then you would have put a SomeOtherWidget into a list of Widget objects. That would be bad, as when you got an object out it might not be a Widget at all.

With the second example, widgets.Add(new SomeOtherWidget()); won't compile. SomeOtherWidget won't be of type T. You will only ever be allowed to call Add on the list with an object of type T, rather than any old IWidget object, so it's able to maintain type safety.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top