I tried this sample in LinqPad:
void Main() { var cats = new [] { new Cat() }; FirstMethod(cats); SecondMethod(cats); } interface Animal { } class Cat : Animal { } void FirstMethod<T>(T a) where T : IEnumerable<Animal> { var b = a.FirstOrDefault(); } void SecondMethod<T>(IEnumerable<T> a) where T : Animal { var b = a.FirstOrDefault(); }
Looking at the generated IL code, there is no difference between the two method calls, and both of them accept cats
as a parameter.
Edit: differences occur in the methods as shown below. (thanks @servy for the comment)
IL_001D: ldarg.0 IL_001E: ldloc.0 // cats IL_001F: call UserQuery.FirstMethod IL_0024: nop IL_0025: ldarg.0 IL_0026: ldloc.0 // cats IL_0027: call UserQuery.SecondMethod FirstMethod: IL_0000: nop IL_0001: ldarg.1 IL_0002: box 02 00 00 1B IL_0007: call System.Linq.Enumerable.FirstOrDefault IL_000C: stloc.0 // b IL_000D: ret SecondMethod: IL_0000: nop IL_0001: ldarg.1 IL_0002: call 05 00 00 2B IL_0007: stloc.0 // b IL_0008: ret
The use of a decompiler in this IL code indicates where boxing occurs for type safety.
private void Main() { Cat[] a = new Cat[1] { new Cat() }; this.FirstMethod<Cat[]>(a); this.SecondMethod<Cat>((IEnumerable<Cat>) a); } private void FirstMethod<T>(T a) where T : IEnumerable<Animal> { Enumerable.FirstOrDefault<Animal>((IEnumerable<Animal>) a); } private void SecondMethod<T>(IEnumerable<T> a) where T : Animal { Enumerable.FirstOrDefault<T>(a); }
Tok ' source share