Does the C # compiler contain special handling for IEnumerable?
Use the Join () method from the String class as an example. When you call it an array of bytes like
byte[] bytes = {3,4,5};
string str = string.Join(",", bytes);
C # compiler maps Join this signature
public static String Join<T>(String separator, IEnumerable<T> values);
However, byte [] is inferred implicitly from the Array class, which is not inferred from the generic IEnumerable, instead it is inferred from the non-equivalent IEnumerable, i.e.
public abstract class Array : ICloneable, IList, ICollection, IEnumerable, IStructuralComparable, IStructuralEquatable {...}
If I do the same with my own interfaces and class that are similar to this case, I get a compiler error as expected, because according to the rules, you cannot use a class coming from an IA interface (not generic IEnumerable) in interface IB (generic IEnumerable) which derives from IA. This means that the C # compiler simply encodes the specific name IEnumerable. Where is this explained?
source to share
However, byte [] is inferred implicitly from the Array class, which is not inferred from the generic IEnumerable, instead it is inferred from the non-equivalent IEnumerable, i.e.
True, but it byte[]
implements IEnumerable<byte>
itself, which makes sense. I'm guessing it's a compiler to compile a specific type for Foo[]
(so everything that comes from Array
basically).
See implemented interfaces at byte[]
(obtained with Type t = typeof(byte[]);
, see property ImplementedInterfaces
):
The first 6 interfaces are probably from Array
, the last 5 interfaces are generic versions 1-6.
source to share
Array is special in the CLR. In particular, only reference array types are covariant. Value types such as byte
are missing. This is how it is. Eric Lippert made a blog post about this ten years ago.
Of the available options, the String.Join
only version that matches byte[]
isString Join<T>(String, IEnumerable<T>)
byte[]
cannot be converted to string[]
, object[]
or IEnumerable<string>
.
Available options ...
String Join(String, IEnumerable<String>)
String Join(String, Object[])
String Join(String, String[])
String Join(String, String[], Int32, Int32)
String Join<T>(String, IEnumerable<T>)
An example of errors like ...
object[] test1 = new byte[0];
string[] test2 = new byte[0];
IEnumerable<string> test3 = new byte[0];
IEnumerable<byte> test4 = new byte[0];
... compiler errors for above ...
Cannot implicitly convert type 'byte[]' to 'object[]'
Cannot implicitly convert type 'byte[]' to 'string[]'
Cannot implicitly convert type 'byte[]' to to 'System.Collections.Generic.IEnumerable<string>'
Other conversion examples
Foo[] test = new OtherFoo[0]; // allowed
OtherFoo[] test = new Foo[0]; // not allowed
public class Foo
{
}
public class OtherFoo : Foo
{
}
source to share