Чтобы использовать универсальную дисперсию в C #, вы должны выполнить все следующие условия:
- Использовать C # 4
- Тип, который изменяется, должен быть универсальныминтерфейс или универсальный делегат
- Параметр типа должен быть помечен "in" (контравариантный) или "out" (ковариантный)
- Аннотации параметра типа должны давать тип, который доказуемо безопасен во всех своих типах.возможные операции
- Аргумент типа «источник» и аргумент типа «место назначения» должны иметь между собой преобразование идентификатора или ссылки.
Ваша программа соответствует условию 1 и условию 5, но неусловия 2, 3 или 4.
Невозможно получить требуемую дисперсию, потому что вы хотите что-то, что будет нарушать условие 4 .Посмотрите, что происходит, когда мы выполняем все условия, кроме условия 4:
// Suppose this declaration were legal:
interface IMyCollection<out T>
{
List<T> Items { get; set; }
}
class Animal {}
class AnimalCollection : IMyCollection<Animal>
{
public List<Animal> { get; set; }
}
class Giraffe : Animal {}
class GiraffeCollection : IMyCollection<Giraffe>
{
public List<Giraffe> { get; set; }
}
static class X
{
public IMyCollection<Animal> GetThing()
{
// IMyCollection is covariant in T, so this is legal.
return new GiraffeCollection();
}
}
class Tiger : Animal {}
...
IMyCollection<Animal> animals = X.GetThing();
// GetThing() actually returns a GiraffeCollection
animals.Items = new List<Animal>() { new Tiger(); }
И в коллекции жирафов теперь есть список животных с тигром.
Вы должны бытьБезопасное использование типов, если вы собираетесь использовать дисперсию. Поскольку компилятор не может определить аннотации дисперсии как безопасные с точки зрения типов, он отклоняет объявление IMyCollection.
Давайте посмотрим, как мы можем это сделать и быть безопасными с точки зрения типов. Проблема в том, что Предметы доступны для записи через интерфейс.
interface IMyCollection<out T>
{
IEnumerable<T> Items { get; }
}
class Animal {}
class AnimalCollection : IMyCollection<Animal>
{
public IEnumerable<Animal> { get { yield return new Tiger(); } }
}
class Giraffe : Animal {}
class GiraffeCollection : IMyCollection<Giraffe>
{
public IEnumerable<Giraffe> { get { yield return new Giraffe(); } }
}
static class X
{
public IMyCollection<Animal> GetThing()
{
return new GiraffeCollection();
}
}
class Tiger : Animal {}
...
MyCollection<Animal> animals = X.GetThing();
// GetThing() actually returns a GiraffeCollection
foreach(Animal animal in animals.Items) { ... }
// Items yields a giraffe, which is an animal
Идеально безопасны.Это будет легальная программа на C # 4.
Если вас интересуют детали разработки ковариации и контравариантности в C # 4, вы можете прочитать мои дюжины статей по этому вопросу.Вы можете найти их здесь:
http://blogs.msdn.com/b/ericlippert/archive/tags/covariance+and+contravariance/
Обратите внимание, что они перечислены в порядке следования самых последних;начните снизу.
Если, в частности, вас интересуют правила определения действительности аннотаций интерфейса, см. эту статью (в которой я только что обнаружил и исправил некоторые ошибки, поэтому я рад, что у нас былоэтот разговор.)
http://blogs.msdn.com/b/ericlippert/archive/2009/12/03/exact-rules-for-variance-validity.aspx