如何使用null目标创建实例方法的委托?

时间:2009-06-04 16:23:35

标签: c# .net delegates

我注意到Delegate类有一个Target属性,(可能)返回委托方法将执行的实例。我想做这样的事情:

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

调用它时,我想做类似的事情:

class A
{
    void Method(int a) {}

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

但是当我尝试构造委托时,我得到一个ArgumentException(委托给一个实例方法不能有一个null'this')。我想做什么,我该怎么做?

3 个答案:

答案 0 :(得分:15)

AHAH! found it!

您可以使用CreateDelegate重载创建一个打开的实例委托,使用一个委托,并明确指定隐含的'this'第一个参数:

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);
    }
}

答案 1 :(得分:1)

要执行此操作,您必须将static方法传递给PossiblyExecuteDelegate()。这将为您提供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);
    }
}

编辑 可以通过反射将委托传递给没有目标的实例方法,但不能使用标准编译代码。

答案 2 :(得分:0)

使用Delegate.CreateDelegate可以完全使用签名的重载:     CreateDelegate (Type, object, MethodInfo)

如果指定&#34; null&#34;对于第二个参数(目标) 然后你必须在委托类型中添加一个额外的参数,它指定实例类型,当你调用委托时,实例必须作为第一个参数传递,然后是&#34; real&#34;方法的参数。

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");
    }
}