How to create a delegate to an instance method wit

2019-01-23 08:03发布

I've noticed that the Delegate class has a Target property, that (presumably) returns the instance the delegate method will execute on. I want to do something like this:

void PossiblyExecuteDelegate(Action<int> method)
{
    if (method.Target == null)   
    {
        // delegate instance target is null
        // do something
    }
    else
    {
         method(10);
         // do something else
    }
}

When calling it, I want to do something like:

class A
{
    void Method(int a) {}

    static void Main(string[] args)
    {
        A a = null;
        Action<int> action = a.Method;
        PossiblyExecuteDelegate(action);
    }
}

But I get an ArgumentException (Delegate to an instance method cannot have a null 'this') when I try to construct the delegate. Is what I want to do possible, and how can I do it?

3条回答
在下西门庆
2楼-- · 2019-01-23 08:20

Ahah! found it!

You can create an open instance delegate using a CreateDelegate overload, using a delegate with the implicit 'this' first argument explicitly specified:

delegate void OpenInstanceDelegate(A instance, int a);

class A
{
    public void Method(int a) {}

    static void Main(string[] args)
    {
        A a = null;
        MethodInfo method = typeof(A).GetMethod("Method");
        OpenInstanceDelegate action = (OpenInstanceDelegate)Delegate.CreateDelegate(typeof(OpenInstanceDelegate), a, method);

        PossiblyExecuteDelegate(action);
    }
}
查看更多
欢心
3楼-- · 2019-01-23 08:20

In order to do this you would have to pass a static method to PossiblyExecuteDelegate(). This will give you a null Target.

class A
{
    void Method(int a) {}
    static void Method2(int a) {}

    static void Main(string[] args)
    {
        PossiblyExecuteDelegate(A.Method2);

        A a = new A();

        PossiblyExecuteDelegate(a.Method);
    }
}

Edit: It is possible to pass a delegate to an instance method with no target via reflection, but not using standard compiled code.

查看更多
再贱就再见
4楼-- · 2019-01-23 08:24

It is possible with Delegate.CreateDelegate, exactly with the overload with the signature: CreateDelegate (Type, object, MethodInfo)

If you specify "null" for the second parameter (target) then you have to put an extra parameter into the delegate type, that specifies the instance type, and when you invoke the delegate, the instance has to be passed as first argument, followed by the "real" parameters of the method.

class Test
{
    public int AddStrings(string a, string b)
    {
        return int.Parse(a) + int.Parse(b);
    }

    static void Main()
    {
        var test = new Test();
        var methodInfo = test.GetType().GetMethod("AddStrings");
        // note the first extra parameter of the Func, is the owner type
        var delegateType = typeof(Func<Test, string, string, int>);
        var del = Delegate.CreateDelegate(delegateType, null, methodInfo);

        var result = (int)del.DynamicInvoke(test, "39", "3");
    }
}
查看更多
登录 后发表回答