Why can "int" be considered as "ushort", but not when it is passed as a parameter in the extension method, and what an elegant solution for it?

I have this extension method:

public static bool In<T>(this T source, params T[] list) { return list.Contains(source); } 

Now I need to use the above method for ushort . When i try

 ushort p = 3; if (p.In(1, 2, 3, 4, 5)) return; 

The first line distinguishes 3 to the ushort hole. But when 3 is passed as a parameter, I get an error

'ushort' does not contain a definition for 'In' and the best extension overload method is 'Extensions.In (T, params T [])' has some invalid arguments.

But it works:

 ushort p = 3; if (Extensions.In(p, 1, 2, 3, 4, 5)) return; 

which is strange.

  • Why does he work with the second example, but not the first?

  • What good alternative will help me? Since there are no literals for short or ushort , I cannot find a simpler alternative than manually casting each integer, such as:

     ushort p = 3; if (p.In((ushort)1, (ushort)2, (ushort)3, (ushort)4, (ushort)5)) return; 
+4
source share
2 answers

Why does he work with the second example, but not the first?

First, let's find out that the compiler tells T Some ushort parameters, and some int . ushort has an implicit conversion to int , and int does not have an implicit conversion to ushort , so T is int .

The key is given in section 7.6.5.2 of the C # 4 specification (emphasis):

The Ci.Mj extension method is eligible if:

  • Ci is not a generic, not nested class
  • The name Mj is an identifier
  • Mj is accessible and applicable when applied to arguments as a static method, as shown above.
  • An implicit conversion of an identity, reference, or box exists from expr to the type of the first parameter Mj.

There is an implicit conversion from ushort to int , but not an identity, reference, or box conversion!

So, the following 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:

 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); } 
+1
source

Well, you define a generic function, so you need to determine the exact type that it has to deal with. Because if you give only numbers ( 1 , 2 , 3 , 4 , etc.) for the function. They may just be something : short , ushort , integer ...

So you can do:

or

 ushort p = 3; if (p.In<ushort>(1, 2, 3, 4, 5)) return; 

Or, as you did in your second example, add each parameter to the type you want:

 ushort p = 3; if (p.In((ushort)1, (ushort)2, (ushort)3, (ushort)4, (ushort)5)) return; 

I personally would prefer the first case.

EDIT

How about why it works in this case:

 ushort p = 3; if (Extensions.In(p, 1, 2, 3, 4, 5)) return; 

is that you explicitly pass as this (first parameter) p , which is a known type for the compiler, so it can output it.

The default type is for 1, 2, 3, 4, etc. - int . Therefore when you call

 p.In(1, 2, 3, 4, 5) 

T treated (or tends to be) as an integer . Since the compiler has no guarantee that there would be no lost data (when you use ushort on integer), it gives an error message. This forces you to explicitly define a smaller type.

Note: function parameters are defined as T[] , so you pass integers (at least the compiler thinks about it), but pretending to be ushort (since you are calling the ext method from p ).

For proof, try running

 int p = 3; if (p.In(1, 2, 3, 4, 5)) return; 

This works great.

+5
source

All Articles