Why does it work with second example, but not first?
First, let's work out what the compiler infers T
to be. Some parameters are ushort
and some are int
. ushort
has an implicit conversion to int
and int
does not have an implicit conversion to ushort
, so T
is int
.
The key here is in section 7.6.5.2 of the C# 4 specification (emphasis mine):
An extension method Ci.Mj is eligible if:
- Ci is a non-generic, non-nested class
- The name of Mj is identifier
- Mj is accessible and applicable when applied to the arguments as a static method as shown above
- An implicit identity, reference or boxing conversion exists from expr to the type of the first parameter of Mj.
There is an implicit conversion from ushort
to int
, but not an identity, reference, or boxing conversion!
So, the following are legal:
Extensions.In<ushort>(p, 1, 2, 3, 4, 5);
Extensions.In<int>(p, 1, 2, 3, 4, 5); // implicit conversion allowed
Extensions.In(p, 1, 2, 3, 4, 5); // T is int
p.In<ushort>(1, 2, 3, 4, 5);
but the following are not:
p.In<int>(1, 2, 3, 4, 5); // implicit conversion not allowed
p.In(1, 2, 3, 4, 5); // T is int
Note that you can get the same error without generics if you define In
as
public static bool In(this int source, params int[] list)
{
return list.Contains(source);
}