Мне нужен метод, который принимает действие (или Func), но действие имеет смешанное количество параметров. Какой самый простой и компактный способ реализации этих перегрузок:
public void Execute<T>(Action<T> action, T param) {
// TODO: Implement something like:
// Execute(action, param, null);
}
public void Execute<T1,T2>(Action<T1,T2> action, T1 param1, T2 param2) {
// TODO: Implement something like:
// Execute(action, param1, param2, null);
}
public void Execute<T1,T2,T3>(Action<T1,T2,T3> action, T1 param1, T2 param2, T3 param3) {
DoStuff();
action(param1, param2, param3)
DoMoreStuff();
}
// OR any other type of higher order function-solution
public void Execute(Action action, params object[] parameters) { ... } // ???
Содержание методов точно такое же, за исключением выполнения действия и его параметров.
Если возможно, не используйте какие-либо специфичные для C # 4.0 функции для решения этой проблемы.
Содержание методов в точности соответствует то же, за исключением исполнения действие и его параметры.
Это кричит для использования функции высшего порядка , но поскольку вы уже параметризовали все изменяющиеся биты (выполнение действия и его параметров), вы уже там. Извините, похоже, вам придется реализовать эти перегрузки вручную.
Простое объединение в цепочку с использованием значений NULL не сработает, поскольку переданные делегаты не совпадают. Что вы можете сделать, так это обернуть переданное действие / функцию в лямбду, чтобы удалить дополнительные аргументы :
public void Execute(Action<T> action, T param) {
Execute( (a, _) => action(a) , param, null);
}
public void Execute(Action<T1, T2> action, T1 param1, T2 param2) {
Execute( (a, b, _) => action(a, b) , param1, param2, null);
}
public void Execute(Action<T1, T2, T3> action, T1 param1, T2 param2, T3 param3) {
DoStuff();
action(param1, param2, param3)
DoMoreStuff();
}
На самом деле это лучший подход (учитывая точку зрения Йоханнеса о том, что вы могли бы также использовать функцию более высокого порядка), поскольку он наиболее удобен для типов (делегаты автоматически быть сопоставленным с правильным числом и типами аргументов) и не требует никаких назойливых вызовов DynamicInvoke
.
Однако ваше последнее определение метода проблематично. Действие Action
по самой своей природе не принимает никаких параметров, поэтому оно не будет хорошо работать с аргументом params object []
. Если вам нужна последняя перегрузка, которая принимает переменное количество аргументов, я бы в конце концов выбрал DynamicInvoke
, только для этого вызова метода:
public void Execute(Delegate action, params object[] parameters)
{
DoStuff();
action.DynamicInvoke(parameters);
DoMoreStuff();
}
Но чтобы расширить то, что говорил Йоханнес, я думаю, что он в основном получал что-то вроде этого:
public Action<T1, T2, T3> CreateAction<T1, T2, T3>(Action action)
{
return (T1 x, T2 y, T3 z) => action();
}
public Action<T1, T2, T3> CreateAction<T1, T2, T3>(Action<T1> action, T1 arg)
{
return (T1 x, T2 y, T3 z) => action(arg);
}
И так далее - другими словами, то, что вы уже сделали, но в общем контексте, чтобы код можно было повторно использовать в других местах.