Перечисление списка объектов в список против IList
Просто наткнулся на это:
Func<List<object>> foo = () => new List<object>();
List<string> s = (List<string>)foo();
IList<string> s1 = (IList<string>)foo();
Компилятор жалуется на листинг в List (имеет смысл), но ничего не говорит о IList. Заставляет меня задаться вопросом, почему?
Ответы
Ответ 1
Компилятор знает, что List<X>
не может быть List<Y>
.
Поэтому он дает ошибку компилятора.
Однако второй прилив может быть успешным, если List<X>
на самом деле является некоторым производным классом, который также реализует IList<Y>
.
Вы получите только ошибку времени компиляции из трансляции, если ни один из них не является интерфейсом, или если один тип является несвязанным интерфейсом, а другой тип запечатан (или структура).
Чтобы процитировать спецификацию (§6.4.2)
Явные ссылочные преобразования:
- От объекта и динамического до любого другого ссылочного типа.
- От любого класса S до любого типа типа T, если S является базовым классом T.
- От любого класса S до любого типа интерфейса T, если S не запечатан и не предоставляется S, не реализует T.
- От любого типа интерфейса S до любого типа типа T, если T не запечатан или не предоставлен T, реализует S.
- От любого типа интерфейса S до любого типа интерфейса T, если S не является производным от T.
- [надрез]
(выделено курсивом)
В предложениях provided...
исключаются фактически неявные преобразования.
Ответ 2
Объект, который известен как List<object>
, может реализовать IList<string>
, а также IList<object>
, поэтому возможно, что приведение может быть успешным. В этом случае это невозможно, поскольку мы знаем, что оператор просто new List<object>()
, но компилятор этого не считает. Возможно, вы расширили List<T>
и внедрили другое, например
// not recommended, but second cast works
public class MyWeirdList : List<object>, IList<string>
Объект, который, как известно, является List<object>
, также не может быть List<string>
, потому что вы можете наследовать только один тип.
public class MyWeirdList : List<object>, List<string> // compiler error
Если List<T>
были запечатаны, оба приведения недействительны, потому что тогда компилятор точно знал, что класс не сможет реализовать IList<string>
. Вы можете попробовать это, используя этот класс:
public sealed class SealedList<T> : List<T> { }
Ответ 3
Первая строка выходит из строя во время компиляции, вторая - "Невозможно передать объект типа" System.Collections.Generic.List 1[System.Object]' to type 'System.Collections.Generic.IList
1 [System.String] '. " исключение во время выполнения.
Если вы посмотрите на этот вопрос (Cast IList <string> на IList <object> не удается во время выполнения), в ответ разъясняется, почему этот компилятор работает, а также предоставляет пример для класса, который мог бы удовлетворять условиям.