Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass a Func<T> with a variable number of parameters

Tags:

c#

func

So I'm attempting to be able to pass a Func with a variable number of parameters.

Something like:

public object GetValue<T>(string name, Func<object> func) { 
    var result = func.DynamicInvoke();
}

The above function/signature works great when the number of arguments to func is know. But it breaks down quickly when you want the number of arguments to be unknown until runtime.

I'd like to change the method signature to allow for the following scenarios, without using method overloading:

// No arguments
var result = GetValue("Bob", () => { return "Bob Smith"; });

// 1 argument
var result = GetValue("Joe", (i) => { return "Joe " + i.ToString(); });

// 2 arguments
var result = GetValue("Henry", (i,e) => { 
    return $"i: {i.ToString()}, e: {e.ToString()}"; 
});

Beyond 2 arguments is not necessary right now.. but may be in the future. The calling syntax is the most important bit to me. I'd prefer to not have the caller cast anything.

I've taken a look at this question and the answers but they all seem to require some calling syntax that I would prefer not to use.

Any ideas how this can be accomplished?

like image 801
Sam Axe Avatar asked Dec 23 '22 07:12

Sam Axe


1 Answers

The answer is don't. First of all, you are attempting to call a method that takes no parameters and returns some object. You can't just "make" a function that requires parameters this type, otherwise how else are you going to invoke it with the required parameters.

You're already creating lambdas, you'll need to close over the "parameters" you want that way you can effectively add additional parameters.

// No arguments
var result = GetValue("Bob", () => { return "Bob Smith"; });

// 1 argument
var i = ...;
var result = GetValue("Joe", () => { return "Joe " + i.ToString(); });

// 2 arguments
var i = ...;
var e = ...;
var result = GetValue("Henry", () => { 
    return $"i: {i.ToString()}, e: {e.ToString()}"; 
});

Otherwise if you truly want to pass in any delegate with any number of parameters, make the parameter Delegate, but you must provide the exact type of the delegate and you must provide the arguments to the call.

public object GetValue<T>(string name, Delegate func, params object[] args) { 
    var result = func.DynamicInvoke(args);
}
var result = GetValue("Bob", new Func<object>(() => { return "Bob Smith"; }));

// 1 argument
var result = GetValue("Joe", new Func<T, object>((i) => { return "Joe " + i.ToString(); }), argI);

// 2 arguments
var result = GetValue("Henry", new Func<T1, T2, object>((i,e) => { 
    return $"i: {i.ToString()}, e: {e.ToString()}"; 
}), argI, argE);
like image 117
Jeff Mercado Avatar answered Dec 25 '22 20:12

Jeff Mercado