Create open instance delegate via reflection

2019-09-19 09:09发布

问题:

Why does the following Delegate.CreateDelegate produce a runtime ArgumentException?

static class Module1
{
    public static void Main()
    {
        MyDataObject mdo = new MyDataObject();
        mdo.DoMagic("Hello");
    }

    #region Assembly A
    public class BusinessObject
    {
    }

    public class MyBusinessObject : BusinessObject
    {

        public void DoMagic(string s)
        {
            Console.WriteLine(s);
        }
    }
    #endregion

    #region Assembly B
    public class MyDataObject
    {
        private delegate void DoMagicDel(BusinessObject bo, string s);

        private DoMagicDel delDoMagic;
        public void DoMagic(string s)
        {
            BusinessObject bo = (BusinessObject)Activator.CreateInstance(Type.GetType("Module1+MyBusinessObject"));
            MethodInfo mi = bo.GetType().GetMethod("DoMagic", BindingFlags.Public | BindingFlags.Instance);
            // ArgumentException: Cannot bind to the target method because its signature or security transparency is not compatible with that of the delegate type.
            delDoMagic = (DoMagicDel)Delegate.CreateDelegate(typeof(DoMagicDel), null, mi);
            delDoMagic(bo, s);
        }
    }
    #endregion
}

Where Assembly A has a project reference to Assembly B but not vice versa. It works when I change first parameter DoMagicMel to type MyBusinessObject. But because assembly B doesn`t know this type of assembly A, this works only in my simplified example:

private delegate void DoMagicDel(MyBusinessObject bo, string s);

Any chance to get this working?

回答1:

ArgumentException: Cannot bind to the target method because its signature or security transparency is not compatible with that of the delegate type.

Why does the following Delegate.CreateDelegate produce a runtime ArgumentException?

  • Because the signature of DoMagicDel does not match the signature of the method described by mi.

Any chance to get this working?

  • Yes, use MakeGenericType to match the signature of mi:

    #region Assembly B
    public class MyDataObject
    {
        public delegate void DoMagicDel<T1>(T1 arg1, string arg2);
        private static Delegate delDoMagic;
        public void DoMagic(string s)
        {
            var bo = Activator.CreateInstance("Module1", "Module1.MyBusinessObject").Unwrap();
            MethodInfo mi = bo.GetType().GetMethod("DoMagic", BindingFlags.Public | BindingFlags.Instance);
            var doMagicDelType = typeof(DoMagicDel<>).MakeGenericType(bo.GetType());            
            if (delDoMagic == null)
                delDoMagic = Delegate.CreateDelegate(doMagicDelType, null, mi);
            delDoMagic.DynamicInvoke(bo, s);
        }
    }
    #endregion
    

I hope I'm not too late ...