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?

+3


source to share


2 answers


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

):



implemented byte array interfaces

The first 6 interfaces are probably from Array

, the last 5 interfaces are generic versions 1-6.

+8


source


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
{
}

      

-3


source







All Articles