Search code examples
.netvb.netreflectiondelegatescontravariance

Create open instance delegate via reflection


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?


Solution

  • 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 ...