Can someone explain how the compiler proceeds here to find the "common" type (double).
I assume the IConvertible plays a role here?
private static void Main(string[] args)
{
    var nrColl = new[] { 1, 2, 0.14, 'a',};
}
				Can someone explain how the compiler proceeds here to find the "common" type (double).
I assume the IConvertible plays a role here?
private static void Main(string[] args)
{
    var nrColl = new[] { 1, 2, 0.14, 'a',};
}
				
                        
                            
                        
                        
                            On
                            
                            
                                                    
                    
                This happens because every type you give it here is implicitly convertable to a double.
When you try to change the char ('a') to a string ("a") you'll notice that it won't work anymore. This is because a character in .Net is nothing more than a UInt16 with some additional methods and different Overrides (for example ToString) and it defines a implicit conversion to double.
Here is a example:
public static void Main()
{
    var bar = new[] { 1, 2, 0.14, 'a', new Foo(42)};
}
public class Foo
{
    public Foo(int value)
    {
        _value = value;
    }
    private int _value;
    public static implicit operator double(Foo foo)
    {
        return foo._value;
    }
}
Interestingly this also works if no direct implicit operator exists, but a chain of multiple implicit operators exists.
public static void Main()
{
    var bar = new[] { 1, 2, 0.14, 'a', new Foo(42)};
}
public class Foo
{
    public Foo(int value)
    {
        _value = value;
    }
    private int _value;
    public static implicit operator int(Foo foo)
    {
        return foo._value;
    }
}
But this 'conversion chaining' only seems to work with internal types for some reason.
This doesn't work:
public static void Main()
{
    var bar = new[] { 1, 2, 0.14, 'a', new Foo(42)};
}
public class Bar
{
    public Bar(int value)
    {
        Value = value;
    }
    public int Value { get; set; }
    public static implicit operator double(Bar bar) => bar.Value;
}
public class Foo
{
    public Foo(int value)
    {
        _value = value;
    }
    private int _value;
    public static implicit operator Bar(Foo foo)
    {
        return new Bar(foo._value);
    }
}
                        
See Finding the best common type of a set of expressions in the specification.
If you follow the steps of how an output type inference is done, you will eventually see that in this case the type variable
Xwill have the lower boundsint,double, andchar.Then, to fix
X,We can try to do that manually.
Let's first examine
int.intcan be implicitly converted todouble, sodoubleis not removed.intcannot be converted tochar, socharis removed. Next we will examinedouble.doublecannot be implicitly converted toint, sointis removed. We are now only left withdouble, and soXis fixed todouble.Basically, if there is exactly one type
Tin the types of the expressions in the array initialiser, that all the other expressions can be implicitly converted to, thenTis the type of the array.