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.