C# run public void functions in loop - c#

I have list of public void function that get one parameter to execute and I want to use loop to do it,
I do not know how to do this, can you advise me?
I thought to insert the names of mt functions to arr and than run in loop
something like this
string[] s1 = new string[3] {"func1", "func2", "func3"};
for(int i=0;i<s1.lengh;i++)
here I want to call the function ... how can I do it?
Do you have better offer?
Thanks.

You can pass functions as parameters / arguments by the use of delegates:
Action<T> action1 = func1;
Action<T> action2 = func2;
where T is the type of the parameter (e.g. int, string)
You can then run these referenced functions by calling
action1(t);
action2(t);
where t is the parameter for your function.
To make this example useful, consider creating a list of actions:
List<Action<T>> actions = new List<Action<T>>();
actions.Add(action1); actions.Add(action2);
foreach (Action<T> action in actions)
{
var t = param; // Replace param with the input parameter
action(t);
}
Of course, you must also have
using System;
at the top of your code file to reference Action.
See also the MSDN documentation on the Action delegate: http://msdn.microsoft.com/en-us/library/018hxwa8.aspx

Your first option is to use delegates (assuming the argument is an integer):
var s1 = new Action<int>[3] { a => func1(a), a => func2(a), a => func3(a) }; // without quotes it creates a function pointer
for(int i=0;i<s1.Length;i++)
s1[i](parameter); // call the delegate
If you do not know the function names at compile time, use reflection to call the method:
var s1 = new string[3] {"func1", "func2", "func3"};
for(int i=0;i<s1.Length;i++)
this.GetType().GetMethod(s1[i]).Invoke(this, new object[] { parameter });
Note the this.GetType() in the second sample - if the methods are defined on another type you will most probably use typeof(OtherType) instead.

Use a delegate. For example, to invoke a method that takes one parameter and returns no value (i.e. returns void), use the Action<T> delegate. Assuming that you want them all to accept the same parameter type, it would look a bit like this:
public void Action1(int x) { ... }
public void Action2(int x) { ... }
public void Action3(int x) { ... }
...
Action<int>[] actions = new Action<int>[] { Action1, Action2, Action3 }
for (int i = 0; i < actions.Length; i++)
{
actions[i](i); // Invoke the delegate with (...)
}
Further Reading
Delegates (C# Programming Guide)

I believe what you are wanting to do could be accomplished via a collection of actions.
Assuming the type of parameter for each function is integer, here's how that could look:
List<Action<int>> functions = new List<Action<int>> {func1, func2, func3};
int i = 5;
foreach (Action<int> f in functions)
{
f(i);
}
EDIT: updated per updated OP that specifies the looping should only be over each of the functions.

var list = new List<Action<MyParameterType>>() {func1, func2, func3};
foreach(var func in list)
{
func(someValue);
}

string[] s1 = new string[3] {"func1", "func2", "func3"};
for(int i=0;i<s1.lengh;i++)
List<string, Func<string>> functionList = new List<string, Func<string>>();
functionList.Add(s1[0], ()=>{return "You called func1!";});
functionList.Add(s1[1], ()=>{return "You called func2!";});
functionList.Add(s1[2], ()=>{return "You called func3!";});
for(int i=0;i<s1.length;i++)
{
string retVal = functionList[s1[i]].Invoke();
}

Related

Passing params object[] through jQuery to C# method

I am trying to pass a params object[] through a jQuery to a C# method. I'm using this to use the same method through jQuery calls, sending a string that would be the real method to call and the params object[] that is the parameters to this call, obviously the number of parameters is unknown since I don't know exactly what method would be call, here is the code on jQuery:
$('#selectComboBox').change(function () {
var data = {
'method': 'GetComboBoxValues',
'arguments': $.param({ Id: this.value })
};
LoadComboBox('/Get/GetJsonResult', data, $('#destionationComboBox'))
})
The LoadComboBox function is a simple function that I centered to populate comboboxes:
function LoadComboBox(url, data, select) {
select.empty();
$.getJSON(url, data, function (a) {
$(a).each(function () {
$(document.createElement('option')).prop('value',this.Value).text(this.Text).appendTo(select);
});
});
}
My C# code is below:
public string GetJsonResult(string method, params object[] arguments)
{
var methodInfo = this.GetType().GetMethod(method);
var l = methodInfo.Invoke(this, arguments);
return new JavaScriptSerializer().Serialize(l);
}
I get arguments as a object array and it is filled with a string Id=1 (with $('#selectComboBox').value being 1). I was not able to perform a Split('=') in a new array because if the real method (GetComboBoxValues) is not expecting a string (in this case is a INT) it would not be dynamically converted.
Do anyone has any tips or clues?
This was a really interesting question. It seems like your main issue is dynamically converting from an object array to a bunch of required parameter types of a dynamically selected method. In short, this can be done using methodInfo.GetParameters(); and using Convert.ChangeType to convert each of your arguments into the appropriate ParameterType. This is probably best seen in action, so I made a small Forms app that does this. Of course, this all makes a ton of assumptions that what is passed in will be "clean" so a lot of error handling is probably in order.
private void button1_Click(object sender, EventArgs e)
{
//mock up some dynamically passed in parameters
var testParams = new List<object>();
testParams.Add("1");
testParams.Add("Hello");
//the args I'm building up to pass to my dynamically chosen method
var myArgs = new List<object>();
//reflection to get the method
var methodInfo = this.GetType().GetMethod("test");
var methodParams = methodInfo.GetParameters();
//loop through teh dynamic parameters, change them to the type of the method parameters, add them to myArgs
var i = 0;
foreach (var p in methodParams)
{
myArgs.Add(Convert.ChangeType(testParams[i], p.ParameterType));
i++;
}
//invoke method
var ans = methodInfo.Invoke(this, myArgs.ToArray());
//display answer
MessageBox.Show((string)ans);
}
public string test(int i, string s)
{
return s + i.ToString();
}
As an aside, in my opinion, this leads to some crazy code that's tough to maintain (you're trying to do things with C# that it wasn't really meant to do). But you didn't really ask anyone's opinion, so I'll leave that as an aside.
Mike Bell lead me to the answer, his idea just needed some adjusments, commented below, the answer was on editing the GetJsonResult method, to this:
public string GetJsonResult(string method, params object[] arguments)
{
var methodInfo = this.GetType().GetMethod(method);
var methodParameters = methodInfo.GetParameters();
var parameters = new List<object>();
for (int i = 0; i < methodParameters.Length; i++)
{
// Here I'm getting the parameter name and value that was sent
// on the arguments array, we need to assume that every
// argument will come as 'parameterName=parameterValue'
var pName = arguments[i].ToString().Split('=')[0];
var pValue = arguments[i].ToString().Split('=')[1];
// This way I can get the exact type for the argument name that I'm sending.
var pInfo = methodParameters.First(x => x.Name == pName);
parameters.Add(Convert.ChangeType(pValue,
// This is needed because we may be sending a parameter that is Nullable.
Nullable.GetUnderlyingType(pInfo.ParameterType) ?? pInfo.ParameterType));
}
var l = methodInfo.Invoke(this, parameters.ToArray());
return new JavaScriptSerializer().Serialize(l);
}

Dynamic invoke of a method using named parameters

We're currently using .NET 3.5 and part of our application uses dynamic invocation (using MethodBase.Invoke)
I am wondering if it is possible to mix in Named Parameters (in .NET 4) with dynamic invocation, to perform something similar to:
// Dictionary that holds parameter name --> object mapping
var parameters = new Dictionary<string, object>();
// Add parameters ....
// Invoke where each parameter will match the one from the method signature.
methodInfo.Invoke(obj, parameters);
Is there any API that allows this option out of the box? If not, is it possible to develop some solution to perform this?
EDIT:
Rethinking of this problem, it sounds similar to how the compiler may actually need to match method calls based on argument lists. Perhaps there's some Compiler API (or the new Roslyn project) that allows doing just this easily? (without coding it myself which may be prone to errors).
You can use code like this:
public static class ReflectionExtensions {
public static object InvokeWithNamedParameters(this MethodBase self, object obj, IDictionary<string, object> namedParameters) {
return self.Invoke(obj, MapParameters(self, namedParameters));
}
public static object[] MapParameters(MethodBase method, IDictionary<string, object> namedParameters)
{
string[] paramNames = method.GetParameters().Select(p => p.Name).ToArray();
object[] parameters = new object[paramNames.Length];
for (int i = 0; i < parameters.Length; ++i)
{
parameters[i] = Type.Missing;
}
foreach (var item in namedParameters)
{
var paramName = item.Key;
var paramIndex = Array.IndexOf(paramNames, paramName);
if (paramIndex >= 0)
{
parameters[paramIndex] = item.Value;
}
}
return parameters;
}
}
And then call it like this:
var parameters = new Dictionary<string, object>();
// Add parameters ...
methodInfo.InvokeWithNamedParameters(obj, parameters);
you can get your paramter names with the help of this article How can you get the names of method parameters? and then you can reorder them to invoke them as described here Reflection: How to Invoke Method with parameters
With .net4, I have an opensource framework ImpromptuInterface (found in nuget) that makes it easy to use the DLR apis for late invocation including named/optional parameters.
var result = Impromptu.InvokeMember(target, "MyMethod", parameters.Select(pair=> InvokeArg.Create(pair.Key, pair.Value)).Cast<object>().ToArray());

How to define a delegate using Delegate.CreateDelegate instead of Func<>?

I have a method and two delegate like below. It is running in this way. But I want to use Delegate.CreateInstance. The types of the dx and the dy must be Func<IEnumerable<Foo>>. Like below the fx and fy. They must not be Func<int, IEnumerable<Foo>>.
public class Test {
private IEnumerable<T> CreateItems<T>(int count) where T : class
{
for (int i = 0; i < count; i++)
{
yield return (T)Activator.CreateInstance(typeof(T), i.ToString());
}
}
public List<T> TestMethod<T>(int i = 1) where T : class
{
return CreateItems<T>(i).ToList();
}
public void TestRun()
{
const int Count = 5;
Func<IEnumerable<Foo>> fx = () => this.TestMethod<Foo>(Count);
Func<IEnumerable<Foo>> fy = () => this.TestMethod<Foo>();
var lfx = fx.Invoke();
var lfy = fy.Invoke();
var dx = Delegate.CreateDelegate( ?? );
var dy = Delegate.CreateDelegate( ?? );
var ldx = dx.DynamicInvoke();
var ldy = dy.DynamicInvoke();
}
}
If you want the type to be Func<IEnumerable<Foo>>, then you cannot create that directly via Delegate.CreateDelegate since they require two parameters: the instance (aka this), and the integer i. Even the form shown in fx has an i - it just happens to be supplied by the compiler. If TestMethod didn't take parameters, it could be done via:
var dy = (Func<IEnumerable<Foo>>) Delegate.CreateDelegate(
typeof(Func<IEnumerable<Foo>>),
this,
GetType().GetMethod("TestMethod").MakeGenericMethod(typeof(Foo))
);
To do this (partial application) dynamically, you would need to create a type that has the instance (this), the value to inject (the i), and a method that calls TestMethod<Foo> with those values. Which is exactly what the compiler does for you here:
Func<IEnumerable<Foo>> fx = () => this.TestMethod<Foo>(Count);
That basically creates:
internal class <>_squiggle {
public Test #this;
public IEnumerable<Foo> Method() {
return #this.TestMethod<Foo>(5);
}
}
and:
var capture = new <>_squiggle { #this = this };
var fx = new Func<IEnumerable<Foo>>(capture.Method);
That's impossible. There is no way you can fit an instance method with signature A F(X x) into a Func<A> directly.
It's possible to bind the first parameter of a method into the delegate directly, but no additional parameters. In your case the instance this is that first parameter, and you can't bind a value for i.
I guess your misunderstanding is how parameters with default values work. They're still parameters that need to be filled in by the caller. It's just that the C# compiler does that for you.
You will need a wrapper of some kind with the correct signature. That can be a lambda, or some other helper method. In your case I'd overload the method TestMethod instead of using a default parameter.

Storing and calling generically-typed delegates

What I'm looking for is probably not going to be possible without resorting to reflection. If that's the case, I'd still want to know the best way to pull it off.
Essentially, this is what I want my code to look like:
var instance = new MyClass();
instance.Add<int, string>(x => x.ToString());
instance.Add<string, Warehouse>(x => Warehouse.LookupByName(x));
instance.Add<Warehouse, IList<Supplier>>(x => x.Suppliers());
instance.Chain(3); // should call each lambda expression in turn
My question is, how can I store these delegates, each with a different signature, in a list in MyClass? And how can I call them later on when I want to, using the return value from each one as the input parameter to the next one?
The inside of MyClass may very well be a mess of List's and all that. But I'm not even sure where to start on this.
(Originally, I wanted to call new MyClass<int, string, Warehouse, IList<Supplier>>(). However, since there's no "type parameter array", I gave up on that approach.)
Well, you could store them all as Delegate - but the tricky thing is invoking them later.
If you're able to validate that the next delegate at any time is of the right type, e.g. by holding a Type reference for "the current output" you could always store a List<Func<object, object>> and make your Add method something like:
public void Add<TIn, TOut>(Func<TIn, TOut> func)
{
// TODO: Consider using IsAssignableFrom etc
if (currentOutputType != typeof(TIn))
{
throw new InvalidOperationException(...);
}
list.Add(o => (object) func((TIn) o));
currentOutputType = typeof(TOut);
}
Then to invoke them all:
object current = ...; // Wherever
foreach (var func in list)
{
current = func(current);
}
The Linq Select statement essentially does this...
var temp = instance.Select(x => x.ToString())
.Select(x => WareHouse.LookupByName(x))
.Select(x=> x.Suppliers());
List<List<Suppliers>> = temp.ToList(); //Evaluate statements
You can also store each intermediate Select call as an Enumerable to have the stated method you use in the OP.
class Program
{
static void Main(string[] args)
{
var instance = new MyClass();
instance.Add<int, string>(i => i.ToString());
instance.Add<string, int>(str => str.Length);
instance.Add<int, int>(i => i*i);
Console.WriteLine(instance.Chain(349));
Console.ReadLine();
}
}
public class MyClass
{
private IList<Delegate> _Delegates = new List<Delegate>();
public void Add<InputType, OutputType>(Func<InputType, OutputType> action)
{
_Delegates.Add(action);
}
public object Chain<InputType>(InputType startingArgument)
{
object currentInputArgument = startingArgument;
for (var i = 0; i < _Delegates.Count(); ++i)
{
var action = _Delegates[i];
currentInputArgument = action.DynamicInvoke(currentInputArgument);
}
return currentInputArgument;
}
}
If you want compile time type checking, what you are doing sounds suspiciously like plain old generic delegates. Assuming that there is some value to storing the individual functions that were Added (other than the Int to String conversion) and composing them later, you can do something like this:
var lookupWarehouseByNumber = new Func<int, Warehouse>(i => Warehouse.LookupByName(i.ToString()));
var getWarehouseSuppliers = new Func<Warehouse, IEnumerable<Supplier>>(w => w.Suppliers);
var getWarehouseSuppliersByNumber = new Func<int, IEnumerable<Supplier>>(i => getWarehouseSuppliers(lookupWarehouseByNumber(i)));

C# - Generic type function is trying to assign result to System.Func(specified type) when a function with parameters is passed in

I'm using a class with a method that looks like the following:
public static T Get<T>(string key, Func<T> method)
{
//do stuff
var obj = method.Invoke();
return (T)obj
}
It works great if it I call it like this:
var x = Get<string>("mykey", test);
Where test is a function that has no parameters and returns a string. However, things break as soon as test has parameters. If I try:
var x = Get<string>("mykey", test(myparam));
I get the error "Argument type "String" is not assignable to parameter type "System.Func< string >".
I know the addition of (myparam) is the problem, but I'm not sure how it should be fixed. Is the issue with how the library's function is written or with how I'm trying to pass in the parameter?
var x = Get<string>("mykey", () => test(myparam));
You can call it like in the following sample code:
Get("mykey", () => test(myparam))
public static T Get<T>(string key, Func<T> method)
{
//do stuff
var obj = method.Invoke();
return (T)obj;
}
void Xyz()
{
int myparam = 0;
var x = Get("mykey", () => test(myparam)); // <string> is not needed
}
double test(int i)
{
return 0.0;
}
You need to curry the parameter by passing a lambda expression that takes no parameters and calls your function with a parameter from elsewhere:
var x = Get<string>("mykey", () => test(myparam));
It's how you're passing the parameter. test(myparam) has type String, and you need to pass a function which returns a String. You can make one with very little effort using a lambda expression:
var x = Get<string>("mykey", () => test(myparam));
The lambda expression () => foo creates a function which, when called, executes and returns foo.
You need to change your Func definition to define the input params thus:
Func<T,T1,T2,T3> method

Categories

Resources