Подтвердить что ты не робот

Почему компилятор не преобразовывает var [] в объект [] в С#?

Нет никакой разницы между этими двумя строками, потому что компилятор во второй строке понимает, что это массив типа int.

var x = new int[] { 1, 2, 3 };   //Fine, x is int[]
var x = new [] { 1, 2, 3 };      //Fine, x is int[]

Но почему я не могу сделать это с разными типами? Почему компилятор не конвертирует мою переменную в тип объект?

var x = new object[] { 1, "df", 5 };   //Fine, x is object[]
var x = new [] { 1, "df", 5 };         //Error! "No best type found for implicity-typed-array"

EDIT:

Спасибо за все ваши ответы. Но я все еще удивляюсь, какие плюсы и минусы делают все выражения, которые компилятор не может преобразовать в тип object? (Потому что я использую нотацию var, что означает, что она не может быть каким-либо типом. Я так понимаю.) Почему компилятор не находит ближайший тип элементов массива, перейдя в дерево наследования?

4b9b3361

Ответ 1

Обозначение new [] предназначено для того, чтобы вы могли вводить явный тип членов массива (или позволять создавать массивы, где его элементы имеют анонимный тип), но его вывод типа ограничен тем, что все элементы должны совместно использовать такого же типа или быть неявно конвертируемым в общий тип, совместно используемый хотя бы одним членом. См. Спецификация С#, раздел 7.6.10.4:

Выражение для создания массива третьей формы называется выражением создания неявно типизированного массива. Он похож на вторую форму, за исключением того, что тип элемента массива явно не указан, но определяется как наилучший общий тип (§7.5.2.14) набора выражений в инициализаторе массива.

Ниже приведены примеры неявно типизированных выражений создания массива:

var a = new[] { 1, 10, 100, 1000 };                       // int[]
var b = new[] { 1, 1.5, 2, 2.5 };                         // double[]
var c = new[,] { { "hello", null }, { "world", "!" } };   // string[,]
var d = new[] { 1, "one", 2, "two" };                     // Error

Последнее выражение вызывает ошибку времени компиляции, так как ни int, ни string неявно конвертируется в другую, и поэтому нет лучшего общего типа. В этом случае должно использоваться явно созданное выражение для создания массива, например, указывая тип object[]. В качестве альтернативы, один из элементов может быть перенесен на общий базовый тип, который затем станет типом предполагаемого элемента.

Ключевым моментом здесь является то, что "лучший общий тип" может быть только одним из уже существующих типов. Как сказал Damien_The_Unbeliever в комментарии: "Поскольку мистер Липперт любит указывать вокруг вывода, всякий раз, когда он ищет лучший общий тип, он будет возвращать только один из типы, которые уже присутствуют, - он не идет на охоту за наиболее распространенным общим предком".

Просто потому, что каждый массив может быть object [] не означает, что он должен. С точки зрения компилятора, который был бы тривиальным выбором последнего курорта, но, я думаю, очень интуитивно понятный для разработчика.

Ответ 2

Чтобы расширить ответ на Joey, рассмотрите этот пример:

interface IFoo { }
interface IBar { }

class A : IFoo, IBar { }
class B : IFoo, IBar { }

var array = new [] { new A(), new B() };

Оба класса реализуют оба интерфейса (а также выводятся из object), поэтому какой тип следует выводить для array?


Чтобы ответить на ваш комментарий, рассмотрите случай, когда A и B используют только один интерфейс:

interface IFoo { }

class A : IFoo { }
class B : IFoo { }

var array = new [] { new A(), new B() };

Оба A и B разделяют object как их базовый класс, но было бы бесполезно и в основном бесполезно выводить это для типа массива. Можно было бы ожидать, что это будет IFoo, если что-нибудь, так что это нарушит принцип наименьшего удивления. Однако это невозможно сделать последовательно, как я показал.

Самое безопасное и наиболее последовательное поведение здесь - это просто не допускать вывода типа.