Перегрузка параметров C # Action и Func - PullRequest
7 голосов
/ 18 августа 2010

Мне нужен метод, который принимает Action (или Func), но Action имеет смешанное количество параметров.Какой самый простой и компактный способ реализации этих перегрузок:

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 для решения этой проблемы.

Ответы [ 2 ]

8 голосов
/ 18 августа 2010

Содержание методов точно то же самое, за исключением исполнения действие и его параметры.

Это кричит об использовании функции более высокого порядка , но, поскольку вы уже параметризовали все биты, которые меняются (выполнение действия и его параметры), вы уже там. Извините, похоже, вам придется реализовать эти перегрузки вручную.

Простое связывание с использованием нулей не будет работать, поскольку переданные делегаты не совпадают. Что вы можете сделать, это обернуть переданный action / func внутри лямбды, чтобы отделить дополнительные аргументы :

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();
}
5 голосов
/ 18 августа 2010

Это на самом деле лучший подход (учитывая, что Йоханнес сказал, что вы могли бы также использовать функцию более высокого порядка), так как он наиболее дружественный к типу (делегаты будут автоматически сопоставляться с правильным числом и типами аргументов) и не требует назойливых вызовов 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);
}

И так далее - другими словами, то, что вы уже сделали, но в общем контексте, так что код можно использовать повторно в других местах.

...