views:

95

answers:

2

Hi,

I was under the impression that the C# compiler will implicitly type an array based off a type that they can all be implicitly converted to.

The compiler generates No best type found for implicitly-typed array

public interface ISomething {}

public interface ISomething2 {}

public interface ISomething3 {}

public class Foo : ISomething { }
public class Bar : ISomething, ISomething2 { }
public class Car : ISomething, ISomething3 { }

void Main()
{
    var obj1 = new Foo();
    var obj2 = new Bar();
    var obj3 = new Car();

    var objects= new [] { obj1, obj2, obj3 };
}

I know that the way to correct this is to declare the type like:

new ISomething [] { obj1, ...} 

But I'm after an under the covers type help here :-)

Thanks

+1  A: 

If the instances can all be cast to the type of any one instance, than that type will be used. It's not enough for all instances to have any type in common, or else the implicity array initialization would always succeed and often generate undesired new object[] arrays.

Sam
+4  A: 

The C# compiler considers the set of types of all the specified elements. It does not consider common base types etc.

You could cast one of the expressions:

var objects= new [] { obj1, obj2, (ISomething) obj3 };

... but personally I'd just use the explicit form:

var objects= new ISomething[] { obj1, obj2, obj3 };

Alternatively, if you explicitly declared any or all of obj1, obj2 and obj3 as type ISomething, that would work fine too without changing the array initialization expression.

From the C# 3 spec, section 7.5.10.4:

An array creation expression of the third form is referred to as an implicitly typed array creation expression. It is similar to the second form, except that the element type of the array is not explicitly given, but determined as the best common type (§7.4.2.13) of the set of expressions in the array initializer.

Section 7.4.2.13 looks like this:

In some cases, a common type needs to be inferred for a set of expressions. In particular, the element types of implicitly typed arrays and the return types of anonymous functions with block bodies are found in this way. Intuitively, given a set of expressions E1…Em this inference should be equivalent to calling a method

Tr M<X>(X x1 … X xm)

with the Ei as arguments. More precisely, the inference starts out with an unfixed type variable X. Output type inferences are then made from each Ei with type X. Finally, X is fixed and the resulting type S is the resulting common type for the expressions.

Jon Skeet