Здравствуйте, yatagarasu, Вы писали:
Y>Почему контейнер IList<IList<T>> нельзя привести к типу IList<IEnumrable<T>> и т.п. ? Y>И как с этим бороться, кроме копирования контейнеров.
простой ответ — прямой запрет. потому что непонятно как конвертировать обратно базовые типы в производные
class A {}
class B : A {}
//...
List<B> bList;
List<A> aList = bList;
aList.Add(new A()); // и как здесь компилятору конвертнуть A в B :xz:
Здравствуйте, Ovl, Вы писали:
Y>>Почему контейнер IList<IList<T>> нельзя привести к типу IList<IEnumrable<T>> и т.п. ? Y>>И как с этим бороться, кроме копирования контейнеров.
Ovl>простой ответ — прямой запрет. потому что непонятно как конвертировать обратно базовые типы в производные
Ovl>
Ovl>class A {}
Ovl>class B : A {}
Ovl>//...
Ovl>List<B> bList;
Ovl>List<A> aList = bList;
Ovl>aList.Add(new A()); // и как здесь компилятору конвертнуть A в B :xz:
Ovl>
Да, логика понятна. Придется всё хранить базовых типах и самому конвертировать в нужного наследника.
Можно конечно обертку написать, но чет лень =)
Сокрытие реализации, мать её =)
Здравствуйте, yatagarasu, Вы писали:
Y>Почему контейнер IList<IList<T>> нельзя привести к типу IList<IEnumrable<T>> и т.п. ?
Потому что при добавлении ко- и контравариантности возникают нетривиальные правила контроля безопасности типов, и в текущей версии C# было решено это не поддерживать. Достаточно сказать, что некоторые случаи приведения типов становятся алгоритмически неразрешимыми (undecidable).
В следущей версии C#, возможно, появится некоторая поддержка ко- и контравариантности для интерфейсов и делегатов. Почитайте замечательную серию заметок об этом на блоге Эрика Липперта.
Здравствуйте, nikov, Вы писали:
N>Потому что при добавлении ко- и контравариантности возникают нетривиальные правила контроля безопасности типов, и в текущей версии C# было решено это не поддерживать. Достаточно сказать, что некоторые случаи приведения типов становятся алгоритмически неразрешимыми (undecidable). N>В следущей версии C#, возможно, появится некоторая поддержка ко- и контравариантности для интерфейсов и делегатов. Почитайте замечательную серию заметок об этом на блоге Эрика Липперта.
Звучит прикольно "Это невозможно... но в следующей версии мы это сделаем".
Хотелось бы услышать о проблемах с безопасностью. Особенно это интересно в свете того, что сам же C# поддерживает (со второй версии) ковариантность для делегатов, а Немерле уже поддерживает ее и для интерфейсов. Например, list (http://nemerle.org/svn/nemerle/trunk/lib/icollection.n) в Немерле реализует ковариантный интерфейс ICovariantList:
public interface ICovariantList [+T]
{
IsEmpty : bool { get; }
Head : T { get; }
CovariantTail : ICovariantList [T] { get; }
}
Правда, реально ковариантностью интерфейсов лично я так и не воспользовался ни разу.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, yatagarasu, Вы писали:
Y>Почему контейнер IList<IList<T>> нельзя привести к типу IList<IEnumrable<T>> и т.п. ? Y>И как с этим бороться, кроме копирования контейнеров.
В некоторых подобных случаях мне помогал такой метод:
class Program
{
class A {}
class B: A {}
static void Trip<T>(IList<T> list)
where T: A
{
Console.WriteLine(list.GetType());
}
static void Main(string[] args)
{
IList<B> list = new List<B>();
Trip(list);
}
}
Здравствуйте, VladD2, Вы писали:
VD>Звучит прикольно "Это невозможно... но в следующей версии мы это сделаем".
Решается это так же, как и все undecidable проблемы — ставится ограничение на количество итераций алгоритма, при превышении которого выдается невразумительная ошибка (типа Expression is too complex to compile). Трудность в том, как обеспечить, чтобы это возникало только уж на совсем экзотических случаях.
VD>Хотелось бы услышать о проблемах с безопасностью.
Все есть на блоге у Эрика.
VD>Особенно это интересно в свете того, что сам же C# поддерживает (со второй версии) ковариантность для делегатов,
В C# 2.0-3.0 поддерживается не ковариантнось делегатов, а ковариантность возвращаемого значения методов, которые привязываются к делегатам. Делегаты разных типов никогда не совместимы по присваиванию.
VD>а Немерле уже поддерживает ее и для интерфейсов.
Ну, проверь.
#pragma indent
using System.Console;
public interface IN[-U] {}
public interface IC[X] : IN[IN[IC[IC[X]]]] {}
module A
Main() : void
def bar : IC[double] = null;
foo : IN[IC[string]] = bar;
Здравствуйте, VladD2, Вы писали:
VD>StackOverflowException. VD>Но это же банальное зацикливание типов. Причем бессмысленное.
Заметь, что это StackOverflowException не в run-time, а при компиляции. Что бы мы ожидали от "умного" компилятора? Что он бы не упал, а сказал бы нам: "Чувак, это же бессмысленное зацикливание типов. Я не буду это компилировать". Undecidablility в данном случае означает, что не существует компилятора, который мог бы безошибочно поставить такой диагноз.
Здравствуйте, VladD2, Вы писали:
VD>Там черт ногу сломит. 8 тем с кучей осбуждений в каждой.
Одинадцать. Причем каждая по своей проблеме... =)
Почитай, почитай — оно того стоит..
Здравствуйте, yatagarasu, Вы писали:
Y>Почему контейнер IList<IList<T>> нельзя привести к типу IList<IEnumrable<T>> и т.п. ? Y>И как с этим бороться, кроме копирования контейнеров.
Посмотри на Umbrella project.
Там есть ListAdapter, который может помочь (он "конвертит" List на лету).