实现接口的数组的隐式类型

我的印象是C#编译器将隐式地键入一个基于一个类型的数组,它们都可以隐式转换为。

编译器为隐式类型数组生成No best type

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

我知道纠正这种情况的方法是声明类型:

 new ISomething [] { obj1, ...} 

但是我在这里找到了封面类型的帮助。

C#编译器会考虑所有指定元素的类型集。 它不考虑常见的基本类型等。

可以转换其中一个表达式:

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

…但我个人只是使​​用明确的forms:

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

或者,如果您将obj1obj2obj3任何一个或全部声明为ISomething类型,那么在不更改数组初始化表达式的情况下也可以正常工作。

从C#3规范,第7.5.10.4节:

第三种forms的数组创建表达式称为隐式类型化数组创建表达式 。 它与第二种forms类似,不同之处在于未明确给出数组的元素类型,而是确定为数组初始值设定项中表达式集的最佳公共类型(第7.4.2.13节)。

第7.4.2.13节看起来像这样:

在某些情况下,需要为一组表达式推断出通用类型。 特别是,以这种方式可以找到隐式类型数组的元素类型和具有块体的匿名函数的返回类型。 直观地,给定一组表达式E1 … Em这个推断应该等同于调用方法

 Tr M(X x1 … X xm) 

以Ei为论据。 更确切地说,推理从一个未固定的类型变量X开始。然后从每个具有类型X的Ei进行输出类型推断。最后,X是固定的,结果类型S是表达式的结果公共类型。

如果实例都可以转换为任何一个实例的类型,那么将使用该类型。 所有实例都没有共同的任何类型是不够的,否则隐含数组初始化将始终成功并且通常会生成不需要的new object[]数组。

作为Skeet的回复的一点点补充:

您可以将其中一个数组项转换为您需要的类型(在这种情况下为接口),或者如果您只有一个该类型的元素(不是派生而是直接类型)。 如

 public static IWindsorInstaller[] MobileRestComponentInstallers { get { return new [] { new RepositoryInstaller(), new AppSettingsInstaller(), // tens of other installers... GetLoggerInstaller() // public IWindsorInstaller GetLoggerInstaller()... }; } } 

这将工作,但请不要这样做:)只需定义数组类型并将new[]更改为new IWindsorinstaller[] 。 在显式定义数组类型的情况下,它更具可读性。

 Do like this for Class object( UIViewController) initialization in var array: var page1 = new Class1(); var page2 = new Class2(); var pages = new UIViewController[] { page1, page2 }; 

注意:这里的UIViewController可以是任何类