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

9

我原本认为C#编译器会隐式地根据可隐式转换的类型自动推断数组的类型。

但实际上,编译器生成了无法找到隐式类型的最佳匹配的错误提示。

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, ...} 

但我需要的是一种“幕后”类型的帮助。


为什么编译器不尝试查找匹配的类型? - Keith Nicholas
4个回答

15

C#编译器会考虑所有指定元素的类型集合,但不会考虑公共基础类型等。

可以对其中一个表达式进行强制转换:

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

...但就我个人而言,我会使用显式表单:

var objects= new ISomething[] { obj1, obj2, obj3 };
如果您明确声明了obj1obj2obj3中的任何一个或全部为类型ISomething,那么这也可以正常工作,而无需更改数组初始化表达式。
从C# 3规范的第7.5.10.4节中得知:
“第三种形式的数组创建表达式称为隐式类型数组创建表达式。它类似于第二种形式,但是数组的元素类型没有被显式给出,而是通过数组初始化程序中一组表达式的最佳公共类型(§7.4.2.13)来确定。”
第7.4.2.13节如下:
“在某些情况下,需要为一组表达式推断出公共类型。特别地,在隐式类型数组的元素类型以及带有块主体的匿名函数的返回类型中找到此类公共类型。直观地说,给定一组表达式E1…Em,应该等价于调用一个方法。”
Tr M<X>(X x1 … X xm)

使用Ei作为参数,更准确地说,推断从一个未固定的类型变量X开始。然后,从每个具有类型X的Ei进行输出类型推断。最终,固定X并且结果类型S是表达式的结果公共类型。


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

0
作为 Skeet 回复的小补充:
你可以将数组中的一个元素强制转换为你需要的类型(在这种情况下是接口),或者如果你只有一个该类型的单个元素(不是派生而是直接类型)。例如:
public static IWindsorInstaller[] MobileRestComponentInstallers
        {
            get
            {
                return new []
                           {
                                 new RepositoryInstaller(),
                                 new AppSettingsInstaller(),
                                 // tens of other installers...
                                 GetLoggerInstaller() // public IWindsorInstaller GetLoggerInstaller()...
                           };
            }
        }

这样做是可行的,但请不要这样做 :) 只需定义数组类型并将 new[] 更改为 new IWindsorinstaller[]。 明确定义数组类型会使代码更易读。


0
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可以是任何类。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接