I have several methods all returning void with different signature (parameters) and different names. I need to pass those methods as a parameter in a generic method that will invoke it latter. Also that need to be as transparent as possible.
Following what I got so far:
private void button1_Click(object sender, EventArgs e)
{
Action<string,int> TestHandler = Test;
InvokeMyMethod(TestHandler);
Action<string, int,object > TestHandlerN = TestN;
InvokeMyMethod(TestHandlerN);
}
public void InvokeMyMethod(Delegate Method)
{
object[] args = new object[X];
Method.DynamicInvoke();
}
public void Test(string t1, int t2)
{
MessageBox.Show(t1 + t2);
}
public void TestN(string t1, int t2, object t3)
{
MessageBox.Show(t1 + t2);
}
That is what I need:
private void button1_Click(object sender, EventArgs e)
{
InvokeMyMethod(Test);
InvokeMyMethod(TestN);
}
public void InvokeMyMethod(XXX_Type Method)
{
object[] args = new object[X];
Method.DynamicInvoke(args);
}
public void Test(string t1, int t2)
{
MessageBox.Show(t1 + t2);
}
public void TestN(string t1, int t2, object t3)
{
MessageBox.Show(t1 + t2);
}
This doesn't answer your question directly, but here is how I solve a similar problem:
public static partial class Lambda
{
public static Action Pin<T0>
(
this Action<T0> action,
T0 arg0
)
{
return () => action(arg0);
}
public static Func<TResult> Pin<T0, TResult>
(
this Func<T0, TResult> func,
T0 arg0
)
{
return () => func(arg0);
}
public static Action Pin<T0, T1>
(
this Action<T0, T1> action,
T0 arg0,
T1 arg1
)
{
return () => action(arg0, arg1);
}
public static Func<TResult> Pin<T0, T1, TResult>
(
this Func<T0, T1, TResult> func,
T0 arg0,
T1 arg1
)
{
return () => func(arg0, arg1);
}
// More signatures omitted for brevity...
// I would love it if C# supported variadic template parameters :-)
}
The idea is that if you have an Action which requires arguments, you can say:
Action<int, string> foo;
Action a = foo.Pin(5, "bleh");
Have the code generator.
Likewise, you might want to have a way to curry to some other delegate type (like Action<string, int>). The difference between my method and yours is that mine is not late-bound, but you do not appear to be using late-binding anyway, so early-binding gives you some compile-time type safety.
I'm not sure you can do what I think you are asking. You call method.DynamicInvoke with some object[], but how did you get values for those parameters?
And to answer the question before anybody asks it, I created the Lambda.Pin functions because I was tired of making this mistake:
Action<int> foo;
foreach (int i in someList)
AddAction(() => foo(i));
public void InvokeMyMethod(Delegate method) {
Method.DynamicInvoke(new object[] {"Test", 1});
}
But you need to invoke it like
InvokeMyMethod((Action<string, int>)Test);
Related
How do I get the arguments 1 and 2 when I only have the Action delegate?
public class Program
{
public static void Main(string[] args)
{
Action act = () => new Program().Test(1, 2);
}
public void Test(int arg1, int arg2)
{
}
}
You cannot. To do that, you would need an Expression<Action> (See Expression in the MSDN) and you cannot convert from an Action to an Expression<Action>, only the other direction.
Further reading
Do you mean something like this:
Action<int,int> act = (a,b) => new Program().Test(a,b);
It could be called than as act(1,2);
It can't be done using an Action, but a lambda expression can also be treated as an Expression<Action> and then it becomes possible.
Note that the code below only works for this kind of expression: it uses the knowledge that we have a method call and that we use constants as parameters.
public class Program
{
public static void Main(string[] args)
{
var values = GetParams(() => Test(1, 2));
foreach (var v in values)
System.Diagnostics.Debug.Print(v.ToString());
}
private object[] GetParams<T>(Expression<Func<T>> expr)
{
var body = (MethodCallExpression)expr.Body;
var args = body.Arguments;
return args.Select(p => ((ConstantExpression)p).Value).ToArray();
}
public int Test(int arg1, int arg2)
{
return arg1 + arg2;
}
}
Consider the following pseudo code:
TResult Foo<TResult>(Func<T1, T2,...,Tn, TResult> f, params object[] args)
{
TResult result = f(args);
return result;
}
The function accepts Func<> with unknown number of generic parameters and a list of the corresponding arguments. Is it possible to write it in C#? How to define and call Foo? How do I pass args to f?
You can use Delegate with DynamicInvoke.
With that, you don't need to handle with object[] in f.
TResult Foo<TResult>(Delegate f, params object[] args)
{
var result = f.DynamicInvoke(args);
return (TResult)Convert.ChangeType(result, typeof(TResult));
}
Usage:
Func<string, int, bool, bool> f = (name, age, active) =>
{
if (name == "Jon" && age == 40 && active)
{
return true;
}
return false;
};
Foo<bool>(f,"Jon", 40, true);
I created a fiddle showing some examples: https://dotnetfiddle.net/LdmOqo
Note:
If you want to use a method group, you need to use an explict casting to Func:
public static bool Method(string name, int age)
{
...
}
var method = (Func<string, int, bool>)Method;
Foo<bool>(method, "Jon", 40);
Fiddle: https://dotnetfiddle.net/3ZPLsY
That's not possible. At best, you could have a delegate that also takes a variable number of arguments, and then have the delegate parse the arguments
TResult Foo<TResult>(Func<object[], TResult> f, params object[] args)
{
TResult result = f(args);
return result;
}
Foo<int>(args =>
{
var name = args[0] as string;
var age = (int) args[1];
//...
return age;
}, arg1, arg2, arg3);
This could become easy with lambda expressions:
TResult Foo<TResult>(Func<TResult> f)
{
return f();
}
Then usage could be like:
var result = Foo<int>(() => method(arg1, arg2, arg3));
Where method can be arbitrary method returning int.
This way you can pass any number of any erguments directly through lambda.
To support asynchoronous code we can define:
Task<TResult> Foo<TResult>(Func<Task<TResult>> f)
{
return f();
}
// or with cancellation token
Task<TResult> Foo<TResult>(Func<CancellationToken, Task<TResult>> f, CancellationToken cancellationToken)
{
return f(cancellationToken);
}
and use it like:
var asyncResult = await Foo(async () => await asyncMethod(arg1, arg2, arg3));
// With cancellation token
var asyncResult = await Foo(
async (ct) => await asyncMethod(arg1, arg2, arg3, ct),
cancellationToken);
You could try something similar to what I posted here: https://stackoverflow.com/a/47556051/4681344
It will allow for any number of arguments, and enforces their types.
public delegate T ParamsAction<T>(params object[] args);
TResult Foo<TResult>(ParamsAction<TResult> f)
{
TResult result = f();
return result;
}
to call it, simply......
Foo(args => MethodToCallback("Bar", 123));
In some cases you may be able to get away with a trick like this:
public static class MyClass
{
private static T CommonWorkMethod<T>(Func<T> wishMultipleArgsFunc)
{
// ... do common preparation
T returnValue = wishMultipleArgsFunc();
// ... do common cleanup
return returnValue;
}
public static int DoCommonWorkNoParams() => CommonWorkMethod<int>(ProduceIntWithNoParams);
public static long DoCommonWorkWithLong(long p1) => CommonWorkMethod<long>(() => ProcessOneLong(p1));
public static string DoCommonWorkWith2Params(int p1, long p2) => CommonWorkMethod<string>(() => ConvertToCollatedString(p1, p2));
private static int ProduceIntWithNoParams() { return 5; }
}
Although it is not really what asked, a simple workaround would be to define several Foo method with different number of type arguments.
It is uncommon to have function with more than 6 parameters, so one could define the following method and get away with almost every use case, while staying type safe. Renan's solution could then be used for the remaining cases.
public TResult Foo<TResult> (Func<TResult> f)
{
return f();
}
public TResult Foo<T1, TResult>(Func<T1, TResult> f, T1 t1)
{
return f(t1);
}
public TResult Foo<T1, T2, TResult>(Func<T1, T2, TResult> f, T1 t1, T2 t2)
{
return f(t1, t2);
}
...
I am trying to write a game with OpenTK.
I want to check the error everytime I call something from GL class.
so, let say, I have this class:
public static class GLCheck
{
public static void Call(function f)
{
// Call f function
CheckError();
}
public static void CheckError()
{
ErrorCode errorCode = GL.GetError();
if (errorCode != ErrorCode.NoError)
Console.WriteLine("Error!");
}
}
so I can call function like this:
GLCheck.Call(GL.ClearColor(Color.White));
GLCheck.Call(GL.MatrixMode(MatrixMode.Modelview));
GLCheck.Call(GL.PushMatrix());
how can I do this?
thanks
----------------- Answer: -----------------
thanks for the answer!
I just realize all answers are using Delegate (Action or Func<>)
On .NET 2.0, this is not available, so you must create your own, here my GLCheck Class:
public static class GLCheck
{
public delegate void Action();
public delegate void Action<T1, T2>(T1 arg1, T2 arg2);
public delegate void Action<T1, T2, T3>(T1 arg1, T2 arg2, T3 arg3);
public delegate void Action<T1, T2, T3, T4>(T1 arg1, T2 arg2, T3 arg3, T4 arg4);
public delegate TResult Func<TResult>();
public delegate TResult Func<T, TResult>(T arg);
public delegate TResult Func<T1, T2, TResult>(T1 arg1, T2 arg2);
public delegate TResult Func<T1, T2, T3, TResult>(T1 arg1, T2 arg2, T3 arg3);
public delegate TResult Func<T1, T2, T3, T4, TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4);
public static void Call(Action callback)
{
callback();
CheckError();
}
public static void Call<T>(Action<T> func, T parameter)
{
func(parameter);
CheckError();
}
}
Once again, thanks for the answer!
It won't be quite as tidy, but you can do this pretty easily with Lambda functions:
GLCheck.Call(() => GL.ClearColor(Color.White));
GLCheck.Call(() => GL.MatrixMode(MatrixMode.Modelview));
GLCheck.Call(() => GL.PushMatrix());
And Call would be defined like this:
public static void Call(Action a)
{
a();
CheckError();
}
In the case of methods GL methods without parameters, you can pass them in a bit more cleanly:
GLCheck.Call(GL.PushMatrix);
(note that there are no () after PushMatrix.)
You can use generics to create something like this:
private void Call<T> (Action<T> func, T parameter)
{
func(parameter);
CheckError();
}
where T would be a parameter. Or you can use exceptions as suggested.
Maybe you should just write your own API on top of the GL, thus resulting in much cleaner code. ie
public class MyGL
{
private TypeHere GL = new TypeHere();
public void ClearColor(Color color)
{
GL.ClearColor(color);
CheckError();
}
private void CheckError()
{
ErrorCode errorCode = GL.GetError();
if (errorCode != ErrorCode.NoError)
Console.WriteLine("Error!");
}
}
And thus you can call it with much more clear and readable code
MyGL.ClearColor(Color.White);
First, foo is a Func<T1,T2,TResult> object.
Is is possible do something like
Func<T2,T1,TResult> bar = ConvertFunction(foo);
thus convert Func<T1,T2,TResult> to Func<T2,T1,TResult>.
Yes, that's possible:
Func<T2, T1, TResult> bar = (t2, t1) => foo(t1, t2);
That basically creates another delegate with switched parameters that internally simply calls the original delegate.
This is the only way to perform this kind of "conversion" if you only have a Func<T1, T2, TResult> and not a Expression<Func<T1, T2, TResult>>.
Here's the function:
class MyFuncConverter<T1, T2, TResult>
{
static Func<T1, T2, TResult> _foo;
public static Func<T2, T1, TResult> ConvertFunction(Func<T1, T2, TResult> foo)
{
_foo = foo;
return new Func<T2, T1, TResult>(MyFunc);
}
private static TResult MyFunc(T2 arg2, T1 arg1)
{
return _foo(arg1, arg2);
}
}
Sample usage:
static void Main(string[] args)
{
var arg1 = 10;
var arg2 = "abc";
// create a Func with parameters in reversed order
Func<string, int, string> testStringInt =
MyFuncConverter<int, string, string>.ConvertFunction(TestIntString);
var result1 = TestIntString(arg1, arg2);
var result2 = testStringInt(arg2, arg1);
// testing results
Console.WriteLine(result1 == result2);
}
/// <summary>
/// Sample method
/// </summary>
private static string TestIntString(int arg1, string arg2)
{
byte[] toEncodeAsBytes = System.Text.ASCIIEncoding.ASCII
.GetBytes(arg2.ToString() + arg1);
string returnValue = System.Convert.ToBase64String(toEncodeAsBytes);
return returnValue;
}
Inisde the callback after BeginInvoke, AsyncResult.AsyncDelegate needs to be cast to proper type, only then EndInvoke is accessible.
But I am using generics, so do I need to define N callbacks for N generalized methods?
This is the class:
public class Async
{
public delegate object Func(); //void with no parameter
public delegate TResult Func<T, TResult>(T arg); //one parameter with result
public static void Execute(IAsyncSubscriber subscriber, Func action)
{
action.BeginInvoke(Callback, subscriber);
}
public static void Execute<T, T1>(IAsyncSubscriber subscriber, T param, Func<T, T1> action)
{
action.BeginInvoke(param, Callback, subscriber);
}
private static void Callback(IAsyncResult ar)
{
AsyncResult result = (AsyncResult)ar;
IAsyncSubscriber subscriber = (IAsyncSubscriber)result.AsyncState;
Func action = (Func) result.AsyncDelegate;
object returnValue = action.EndInvoke(result); //To call endinvoke
subscriber.Callback(returnValue);
}
}
There are a few ways in which you can avoid defining N callbacks:
You can pass the corresponding EndInvoke method as state in the BeginInvoke call. e.g.
private delegate T EndInvokeDelegate<T>(IAsyncResult ar);
public static void Execute<T, T1>(IAsyncSubscriber subscriber, T param, Func<T, T1> action)
{
action.BeginInvoke(param, Callback<T1>, new object[]{subscriber, new new EndInvokeDelegate<T1>(action.EndInvoke)});
}
public static void Execute<T, T1, T2>(IAsyncSubscriber subscriber, T param1, T1 param2, Func<T, T1, T2> action)
{
action.BeginInvoke(param1, param2, Callback<T2>, new object[]{subscriber, new new EndInvokeDelegate<T2>(action.EndInvoke)});
}
private static void Callback<TR>(IAsyncResult ar)
{
object[] stateArr = (object[])ar.AsyncState;
IAsyncSubscriber subscriber = (IAsyncSubscriber)stateArr[0];
EndInvokeDelegate<TR> action = (EndInvokeDelegate<TR>)stateArray[1];
TR returnValue = action(ar);
subscriber.Callback(returnValue);
}
You can also make Callback non-generic by treating stateArray[1] as MultiCastDelegate and using DynamicInvoke on it but that would be slow.
For .Net 2.0 and 3.0, you can use reflection e.g.
Type actionType= result.AsyncDelegate.GetType();
var minfo = actionType.GetMethod("EndInvoke");
object returnValue = minfo.Invoke(res.AsyncDelegate, new object[] { ar });
For .Net 4.0, you can use dynamic. e.g.
dynamic action = result.AsyncDelegate;
object returnValue = action.EndInvoke(result);
If I understand correctly, your assumption is correct. You will need to define N callbacks.
On the bright side, you will only be doing this once, so no biggy, just a little repetitive work :)