Универсальный интерфейс с общим ограничением не может быть приведен - PullRequest
2 голосов
/ 15 мая 2019

У меня есть общий интерфейс, который имеет ограничение интерфейса, которое из-за ковариации я не могу разыграть, как я хочу. и приходится полагаться на динамику. В идеале я хочу отойти от этого, но не могу найти способ сделать это.

Мы можем считать эту проблему похожей на контроллеры WebApi. У меня будет строка, входящая вместе с полезной нагрузкой. В зависимости от имени строки мне нужно выбрать подходящую «стратегию» (контроллер / метод) для запуска и передачи полезной нагрузки.

Я также хочу, чтобы это работало автоматически, что означает: у меня есть некоторый «отраженный» код, который ищет все классы, которые используют IAnimalAction <>, загружает их в коллекцию и устанавливает контейнер DI. Все это работает правильно.

Как вы можете видеть в коде, динамика работает отлично, однако я хотел бы избежать исключений во время выполнения и иметь их во время сборки.

 public interface IAnimalType
    { }

    public class Cat : IAnimalType
    { public string Name;} 
    public class Dog : IAnimalType
    { public int EvilFactor;} 
    public class Cow : IAnimalType
    { }

    public interface IAnimalAction<T> where T : IAnimalType
    {
        bool ActUpon(T input);
    }
    public class IgnoreAnimal: IAnimalAction<Cat>
    {
        public bool ActUpon(Cat input)
        {
            return true;
        }
    }
    public class LoveAnimal: IAnimalAction<Dog>, IAnimalAction<Cow>
    {
        public bool ActUpon(Dog input)
        {
            return true;
        }

        public bool ActUpon(Cow input)
        {
            return true;
        }
    }

    public class test
    {
        public test()
        {
            var cat = new Cat();
            var ignoreAction= SomeStaticInstance.GetRelevantAction(cat. GetType().Name);// returns new IgnoreAnimal(); in this case
            var works = ((IAnimalAction<Cat>)ignoreAction).ActUpon(cat);
            var alsoWorks= ((dynamic)ignoreAction).ActUpon(cat);
            var doesnt= ((IAnimalAction<IAnimalType>)ignoreAction).ActUpon(constraint);


        }
    }

Я бы хотел убедиться, что метод ActUpon всегда будет доступен в моих экземплярах.

Я понимаю проблему с ковариацией и контравариантностью, но я думаю, что должен быть какой-то другой способ, который не зависит от динамики.

Так как я загружаю свои классы с помощью отражения и загружаю только те классы, которые реализуют «интерфейс IAnimalAction», я думаю, что безопасно оставить все как есть, с опцией, ищущей имя метода в интерфейсе, и чтобы код вызывал разрешенный имя метода, а не жесткий код ActUpon.

Обновлен пример, чтобы он стал немного менее абстрактным

...