Могу ли я использовать параметры в делегатах Action или Func?

Когда я пытаюсь использовать параметры в делегате действия...

private Action<string, params object[]> WriteToLogCallBack;

Я получил эту ошибку времени разработки:

Недопустимые параметры токена в объявлении члена класса, структуры или интерфейса.

Любая помощь!


person Homam    schedule 30.10.2010    source источник
comment
params не является типом, т.е. вы можете использовать ref в определении типа?   -  person Saeed Amiri    schedule 30.10.2010


Ответы (5)


Как насчет этого обходного пути?

private Action<string, object[]> writeToLogCallBack;
public void WriteToLogCallBack(string s, params object[] args)
{
  if(writeToLogCallBack!=null)
    writeToLogCallBack(s,args);
}

Или вы можете определить свой собственный тип делегата:

delegate void LogAction(string s, params object[] args);
person CodesInChaos    schedule 30.10.2010
comment
Как вы называете это с лямбдой? - person toddmo; 24.02.2017

Параметры типа Variadic невозможны в C#.

Вот почему существует множество объявлений, например, для Action<...>, Func<...> и Tuple<...>. Хотя это была бы интересная функция. C++0x имеет их.

person Jordão    schedule 30.10.2010
comment
Не уверен, насколько хорошо это будет работать с дженериками (в отличие от шаблонов). - person CodesInChaos; 30.10.2010

Вы можете попробовать это. Он допускает любое количество аргументов, и вы получите ошибку времени компиляции, если передадите неправильное количество или тип аргументов.

public delegate T ParamsAction<T>(params object[] oArgs);

public static T LogAction<T>(string s, ParamsAction<T> oCallback)
{
    Log(s);
    T result = oCallback();
    return T;
}

Foo foo = LogAction<Foo>("Hello world.", aoArgs => GetFoo(1,"",'',1.1));
person Bryan Clark    schedule 29.11.2017
comment
Это действительно хороший способ сделать это... Отличная работа, сэр. - person Gwasshoppa; 23.08.2018
comment
Удивительный кусок кода здесь, Брайан. Ниже я добавил незначительное расширение к приведенному выше коду, чтобы показать, как обернуть вызовы нескольких методов. Я использую это, чтобы объединить несколько методов, содержащих вызовы базы данных, в одну транзакцию. Спасибо Брайан :-) - person kamgman; 23.08.2018
comment
Это должно было возвращать результат вместо T? - person Mark Lauter; 01.11.2018
comment
какой в ​​этом смысл, если ты не можешь LogAction<Foo>("Hello world.", (p1,p2,p3) => GetFoo(p1,p2,p3));??? минус.... - person Philipp Munin; 16.08.2019

Вы можете использовать params в фактическом объявлении делегата, но не в его типе. Общие параметры действия — это только типы, а не фактические аргументы, которые должны передаваться при вызове делегата. params - это не тип, это ключевое слово.

person Gordon Gustafson    schedule 30.10.2010

Я немного расширил приведенный выше код от Брайана, чтобы показать, как обернуть несколько вызовов методов.
Я использую это, чтобы обернуть несколько методов, содержащих вызовы базы данных, в одну транзакцию.
Спасибо, Брайан :- )
(Вы можете запустить в LINQPad следующее для проверки)

//Wrapper code
public delegate void MyAction(params object[] objArgs);
public static void RunActions(params MyAction[] actnArgs)
{
    Console.WriteLine("WrapperBefore: Begin transaction code\n");
    actnArgs.ToList().ForEach( actn =>  actn() );
    Console.WriteLine("\nWrapperAfter: Commit transaction code");
}

//Methods being called
public void Hash  (string s, int i, int j)  => Console.WriteLine("   Hash-method call: " + s + "###" + i.ToString() + j.ToString());
public void Slash (int i, string s)         => Console.WriteLine("   Slash-method call: " + i.ToString()+ @"////" + s);

//Actual calling code
void Main()
{  
  RunActions( objArgs => Hash("One", 2, 1)
             ,objArgs => Slash(3, "four")   );
}

//Resulting output: 
// 
//  WrapperBefore: Begin transaction code
//  
//  Hash-method call: One###21
//  Slash-method call: 3////four
//  
//  WrapperAfter: Commit transaction code  
person kamgman    schedule 23.08.2018