Can I use params in Action or Func delegates?
Asked Answered
V

5

53

When I'm trying to use params in an Action delegate...

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

I received this design time error:

Invalid token 'params' in class, struct, or interface member declaration

Any help!

Vergne answered 30/10, 2010 at 16:36 Comment(1)
params is not a type, i.e you can use ref in type definition?Zebu
H
51

How about this workaround?

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

Or you could define your own delegate type:

delegate void LogAction(string s, params object[] args);
Harris answered 30/10, 2010 at 16:47 Comment(1)
How do you call this with a lambda?Downtrodden
U
12

Variadic type parameters are not possible in C#.

That's why there're many declarations for Action<...>, Func<...>, and Tuple<...>, for example. It would be an interesting feature, though. C++0x has them.

Unquiet answered 30/10, 2010 at 16:54 Comment(1)
Not sure how well it would work with generics (as opposed to templates).Harris
A
7

You could try this. It allows for any number of arguments, and you'll get a compile time error if you pass the wrong number or type of arguments.

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

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

Foo foo = LogAction<Foo>("Hello world.", aoArgs => GetFoo(1,"",'',1.1));
Argillaceous answered 29/11, 2017 at 15:15 Comment(4)
This is a really nice way of doing it... Nice work sirRamonitaramos
Awesome piece of code here Bryan. I have added below a minor extension to the above code to show how to wrap multiple method calls. I am using this to wrap multiple methods that contain database calls, into a single transaction. Thanks Bryan :-)Precipitancy
Was this supposed to return result instead of T?Turcotte
what's the point of it if you cannot do LogAction<Foo>("Hello world.", (p1,p2,p3) => GetFoo(p1,p2,p3));??? minusing....Freud
U
3

You can use params in the actual declaration of a delegate, but not in type of one. The generic parameters to an Action are only types, not the actual arguments to be passed when invoking the delegate. params is not a type, it is a keyword.

Unriddle answered 30/10, 2010 at 16:50 Comment(0)
P
2

I have done a minor extension to the above code from Bryan, to show how to wrap multiple method calls.
I am using this to wrap multiple methods that contain database calls, into a single transaction.
Thanks Bryan :-)
(You can run the following in LINQPad to test)

//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  
Precipitancy answered 23/8, 2018 at 1:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.