Можно ли в этой гипотетической ситуации выполнить конечную прогону ковариации дженериков в C # <4? - PullRequest
3 голосов
/ 07 мая 2010

Предположим, у меня есть небольшая иерархия наследования животных:

public interface IAnimal {
    string Speak();
}

public class Animal : IAnimal {
    public Animal() {}
    public string Speak() {
        return "[Animal] Growl!";
    }
}

public class Ape : IAnimal {
    public string Speak() {
        return "[Ape] Rawrrrrrrr!";
    }
}

public class Bat : IAnimal {
    public string Speak() {
        return "[Bat] Screeeeeee!";
    }
}

Далее представлен интерфейс, предлагающий способ превращения strings в IAnimals.

public interface ITransmogrifier<T> where T : IAnimal {
    T Transmogrify(string s);
}

И, наконец, вот одна стратегия для этого:

public class Transmogrifier<T> : ITransmogrifier<T> where T : IAnimal, new() {
    public T Transmogrify(string s) {
        T t = default(T);
        if (typeof(T).Name == s)
            t = new T();
        return t;
    }
}

Теперь вопрос. Можно ли заменить разделы, отмеченные [1], [2] и [3], чтобы эта программа правильно компилировалась и работала? Если вы не можете сделать это, не касаясь частей, отличных от [1], [2] и [3], можете ли вы получить IAnimal из каждого экземпляра Transmogrifier в коллекции, содержащей произвольные реализации IAnimal? Можете ли вы даже создать такую ​​коллекцию для начала?

    static void Main(string[] args) {
        var t = new Transmogrifier<Ape>();
        Ape a = t.Transmogrify("Ape");
        Console.WriteLine(a.Speak());  // Works!

        // But can we make an arbitrary collection of such animals?
        var list = new List<Transmogrifier< [1] >>() {
            // [2]
        };

        // And how about we call Transmogrify() on each one?
        foreach (/* [3] */ transmogrifier in list) {
            IAnimal ia = transmogrifier.Transmogrify("Bat");
        }
    }
}

Ответы [ 2 ]

4 голосов
/ 08 мая 2010

Ли прав.

Как вы подразумеваете под своим вопросом, вы можете сделать это в C # 4, пометив ITransmogrifier как ковариант ("out") в T. Затем вы можете создать List<ITransmogrifier<IAnimal>> и поместить Transmogrifier<Bat> в этот список.

3 голосов
/ 07 мая 2010

Вы не можете сделать это, так как между Transmorgifier<Ape> и Transmorgifier<Bat> нет связи типов, поэтому вы не можете поместить их в один общий список (за исключением List<object>). Очевидное решение - просто сделать ITransmorgifier неуниверсальным:

public interface ITransmogrifier
{
    IAnimal Transmogrify(string s);
}

Тогда вы могли бы иметь

var list = new List<ITransmogrifier>() {
    new Transmorgifier<Ape>(), new Transmorgifier<Bat>() ...
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...