Click here to Skip to main content
15,846,211 members
Please Sign up or sign in to vote.
4.75/5 (4 votes)
See more:
Hello,

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:
C#
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(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);
}

That is what I need:
C#
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);
        }


Thank You
Posted
Comments
dasblinkenlight 4-Mar-11 15:03pm    
1. Considering that you contemplate using DynamicInvoke anyway, what is wrong with the code you have?
2. Where do the parameters come from? I mean, at some point your code would need to learn the value of X in the call of new object[X]; where does it come from?
Vitor Mello 4-Mar-11 19:13pm    
The object[X] come from another place and it isn't the issue let suppose for this sample that is OK. The problem with my implementation now is that I need to create Actions for each Method that I want to pass and that action as a parameters, I need that process to be transparent, passing only the method.

As far as I know (and I was confronted with the same problem and studied it), sadly, this cannot be done.
The closest I could manage was something like this:
C#
private void button1_Click(object sender, EventArgs e)
{
    InvokeMyMethod(Test, "string", 1);
    InvokeMyMethod(TestN, "other string", 3, Color.Red);
}

public delegate void MyMethodDelegate(params object[] args);

public void InvokeMyMethod(MyMethodDelegate method, params object[] args)
{
    method.DynamicInvoke(args);
}

public void Test(params object[] args)
{
    if (args.Length < 2) return;
    MessageBox.Show(string.Format("{0}{1}", args[0], args[1]));
}

public void TestN(params object[] args)
{
    // or, whatewer
    if (args.Length < 3) return;
    MessageBox.Show(string.Format("{0}{1}{2}", args[0], args[1], args[2]));
}
 
Share this answer
 
v2
Comments
Vitor Mello 4-Mar-11 14:52pm    
There is any way to do that without have to follow the generic (params object[] args) signature ???
Sergey Alexandrovich Kryukov 4-Mar-11 15:15pm    
Yes, see my answer, but this is simply a syntactic candy over array.
I think my Answer provide most generic cases you may need to consider.
--SA
koenigs 27-Oct-16 22:53pm    
And where is your answer please? I don't see it
To let you pass a method group (a fancy way to call a delegate defined by a plain method name) the compiler must know the exact types of all delegate's parameters. The closest you could get to the syntax you want would still require you to list parameter types explicitly. You would also need to define N nearly identical generic methods, where N is the max number of parameters your target functions take.
C#
public static void Main() {
    Invoke<long>(Test);
    Invoke<string,int>(Test);
    Invoke<string,int,object>(Test);
}
private static void Invoke<T1>(Action<T1> a) {
    InvokeMyMethod(a);
}
private static void Invoke<T1,T2>(Action<T1,T2> a) {
    InvokeMyMethod(a);
}
private static void Invoke<T1,T2,T3>(Action<T1,T2,T3> a) {
    InvokeMyMethod(a);
}
private static void InvokeMyMethod(Delegate method) {
    var args = new object[X]; // do your magic here
    method.DynamicInvoke(args);
}
public static void Test(long t) {
}
public static void Test(string t1, int t2) {
}
public static void Test(string t1, int t2, object t3) {
}
 
Share this answer
 
It's quite simple if you use fixed number of different delegates with the signatures defined in advance. Each delegate type will have fixed number of parameters (you can also use params syntax to mimic unlimited number of parameters of the same type, but this is only a syntactic candy). Of course, it will include the usual polymorphism in parameter classes. You can also create and use generic delegates, not only those covered by System.Action or System.Func.

In this case, the usage will not require any type cast, so it won't be an invitation for bugs and mess-ups. If you want to expose more "dynamic" indirection feature, I would say, it wouldn't worth the effort and you should reconsider you approach.

Consider this:

C#
delegate void MySimpleDelegate(int a, string b, DelegateUser user);
delegate void MySimpleDelegateWithParamsArray(DelegateUser user, int a, params string[] b);
delegate int MyDelegateWithByRef(int a, ref string b);
delegate int MyDelegateWithOut(int a, string b, out string c);
delegate void MyGenericDelegate<FIRST, SECOND>( //same as System.Action
    DelegateUser user,
    FIRST first,
    SECOND second); 

class DelegateUser {
    internal void Call(MySimpleDelegate[] methods, int a, string b) {
        foreach (MySimpleDelegate methodInstance in methods)
            methodInstance(a, b, this);
    } //Call
    internal void Call(MySimpleDelegateWithParamsArray[] methods, int a, params string[] b) {
        foreach (MySimpleDelegateWithParamsArray methodInstance in methods)
            methodInstance(this, a, b);
    } //Call
    internal void Call(MyDelegateWithByRef method, int a, ref string b) {
        method(a, ref b);
    } //Call
    internal void Call(MyDelegateWithOut method, int a, string b, out string c) {
        method(a, b, out c);
    } //Call
    internal void Call<FIRST, SECOND>(
        MyGenericDelegate<FIRST, SECOND>[] methods,
        DelegateUser user, FIRST first, SECOND second) {
            foreach (MyGenericDelegate<FIRST, SECOND> methodInstance in methods)
                methodInstance(this, first, second);
    } //Call
    internal string Value { get; set; }
    //...
} //class DelegateUser

//usage example:
class Test {
    void TestCalls() {
        DelegateUser user = new DelegateUser();
        user.Call<int, double>(new MyGenericDelegate<int, double>[] {
            delegate(DelegateUser userRef, int iValue, double dValue) {
                user.Value =
                    string.Format("Firt: {0}: {1}, {2}",
                    user.Value, iValue, dValue);
            },
            delegate(DelegateUser userRef, int iValue, double dValue) {
                user.Value =
                    string.Format("Second: {0}: {1}, {2}",
                    user.Value, iValue, dValue);
            }
        }, user, 3, 3d);
    }
} //class Test



This class makes no sense, it's only to demonstrate the syntax. For giggles, I also added array of delegates, but it is not usually needed, because each delegate instance is mult-cast, so the other (better) way of doing is adding multiple method to the same delegate instance.

This technique is only useful if a delegate code and you calling class code are doing something together. For example, a delegate could operate on instance of the class passed as a parameter: you class calculates a parameter, you delegate instance add custom processing to it.

Very usual case is working on collection. For example, a calling class provides an iterator to work with some collection of objects, and the delegate instance performs some custom processing for each of the collection members, using foreach loop. For explanation of such techniques, please see my old Answer here: What are the advantages of delegates in C#.NET?[^].

—SA
 
Share this answer
 
v2

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900