Вы не можете делать то, что пытаетесь сделать.
actions.Add(new Foo()); // expects and returns string
actions.Add(new Bar()); // expects and returns int
object obj;
foreach(var item in actions)
obj = item.Execute(obj);
Если Foo
ожидает string
, а Bar
ожидает int
(и технически любая реализация может ожидать любой другой тип), то какое значение вы можете передать каждому элементу в коллекции, который будетработать со всеми из них?Кроме того, что бы вы сделали с возвращаемыми значениями, поскольку каждое из них могло бы быть разного типа?
Вы можете решить проблему получения compile , объявив входы и выходы какobject
, хотя это лишило бы смысла сделать его общим.Вы бы просто заменили свой базовый класс на этот ...
public abstract class Action
{
public abstract object Execute(object input);
}
... но это не очень полезный класс.
Но настоящая проблема в том, что методы, которые получают и возвращают object
, не , как правило, , также очень полезны.Система типов позволяет нам знать типы аргументов, возвращаемых значений, переменных и т. Д. Это часть того, что указывает на намерения нашего кода.Например, мы пишем метод, подобный этому:
bool IsAnagram(string input)
, потому что мы хотим знать , если (bool
), то input (string
) равенанаграмма.Знание того, что оно делает, и есть наша причина для этого.Если мы не хотим знать, является ли string
анаграммой, мы не вызываем этот метод, потому что он нам не нужен.
Но что, если у нас есть такой метод:
object GetResult(object input)
У него нет оснований для существования.Почему мы бы это назвали?Если у нас есть значение некоторого типа, и мы хотим что-то с ним сделать и получить какой-то результат, мы напишем метод, который это делает.
Аналогично, если мы вернемся object
из метода, чтомы делаем с этим?Мы не знаем что это.Это немного похоже на поход в магазин, чтобы что-то купить, за исключением того, что мы не имеем в виду, что мы хотим купить, и они вручают нам посылку, а мы не знаем, что внутри.У нас не могло быть никаких планов относительно того, что мы намеревались сделать, когда мы получили это, так как мы не знали, что мы получим.Так что мы просто не будем этого делать.
Имеет смысл использовать object
только в определенных сценариях, где нам все равно, что это за тип.Эти сценарии встречаются реже, потому что для того, чтобы наше приложение могло что-либо делать, ему почти всегда нужно что-то делать с указанными типами - создавать их, получать их откуда-то, передавать их другим методам и получать больше ожидаемых типов взамен.
Если вы просто хотите, чтобы коллекция делала , и все они принимали разные аргументы и возвращали разные типы, тогда вы должны объявить коллекцию в соответствии с наименьшим общим знаменателем, которыйэто просто Action
без аргументов и без возвращаемых значений.
Вы можете сделать это:
var actions = new List<Action>();
actions.Add(() =>
{
var foo = new Foo();
foo.Execute(5);
});
actions.Add(() =>
{
var bar = new Bar();
bar.Execute("Hello!");
});
foreach (var action in actions)
{
action.Invoke();
}
... и могут быть случаи, когда коллекцияAction
полезно.Но в большинстве случаев нет причин предпринимать кучу несвязанных действий, которые делают разные вещи, и помещать их в коллекцию друг с другом.