У меня есть общий интерфейс, который имеет ограничение интерфейса, которое из-за
ковариации я не могу разыграть, как я хочу. и приходится полагаться на динамику. В идеале я хочу отойти от этого, но не могу найти способ сделать это.
Мы можем считать эту проблему похожей на контроллеры 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.
Обновлен пример, чтобы он стал немного менее абстрактным