2017-08-20 46 views
2

在此示例代码中,我试图从il生成器调用匿名操作。我不确定是否以及如何将参考加载到委托以及如何调用它。 我可以做到这一点,如果OnFunctionCall是一个静态方法,而不是属性。如何从il生成器中调用Action <string,bool>

public delegate void TestDelegate(); 

public static class ExampleOne 
{ 
    public static Action<string, bool> OnFunctionCall 
     => (message, flag) => Console.WriteLine("Example"); 
} 

public static class ExampleTwo 
{ 
    public static TType CreateDelegate<TType>(Action<string, bool> onFunctionCall) 
     where TType : class 
    { 
     var method = new DynamicMethod($"{Guid.NewGuid()}", typeof(void), Type.EmptyTypes, typeof(TType), true); 

     ILGenerator il = method.GetILGenerator(); 

     // Emit some code that invoke unmanaged function ... 

     // loading the first string argument 
     il.Emit(OpCodes.Ldstr, method.Name); 

     // not sure here how to load boolean value to the stack 
     il.Emit(OpCodes.Ldc_I4_0); 

     // this line doesn't work 
     // example two has no idea about ExampleOne 
     // is it possible to load the reference of the Action<string, bool> to the stack and call it ? 
     il.Emit(OpCodes.Call, onFunctionCall.Method); 

     il.Emit(OpCodes.Ret); 

     return method.CreateDelegate(typeof(TestDelegate)) as TType; 
    } 
} 

public class Program 
{ 
    public static void Main(string[] args) 
     => ExampleTwo 
      .CreateDelegate<TestDelegate>(ExampleOne.OnFunctionCall) 
      .Invoke(); 
} 
+0

这比CodeDOM更容易使用CodeDOM比Reflection Emit – MickyD

+0

@MickyD你能否提供一个示例 – ptp

+0

@MickyD它也必须与net standard 2.0兼容 – ptp

回答

2

您必须传递想要调用委托的信息。方便的方法是接受MemberExpression,否则接受MemberInfo也可以。看看您的修改后的代码:

public delegate void TestDelegate(); 

public static class ExampleOne 
{ 
    public static Action<string, bool> OnFunctionCall 
     => (message, flag) => Console.WriteLine("OnFunctionCall"); 

    public static Action<string, bool> OnFunctionCallField 
     = (message, flag) => Console.WriteLine("OnFunctionCallField"); 
} 

public static class ExampleTwo 
{ 
    public static TType CreateDelegate<TType>(Expression<Func<object>> expression) 
     where TType : class 
    { 
     var body = expression.Body as MemberExpression; 
     if (body == null) 
     { 
      throw new ArgumentException(nameof(expression)); 
     } 

     var method = new DynamicMethod($"{Guid.NewGuid()}", typeof(void), Type.EmptyTypes, typeof(TType), true); 

     ILGenerator il = method.GetILGenerator(); 

     // Get typed invoke method and 
     // call getter or load field 
     MethodInfo invoke; 
     if (body.Member is PropertyInfo pi) 
     { 
      invoke = pi.PropertyType.GetMethod("Invoke"); 
      il.Emit(OpCodes.Call, pi.GetGetMethod()); 
     } 
     else if (body.Member is FieldInfo fi) 
     { 
      invoke = fi.FieldType.GetMethod("Invoke"); 
      il.Emit(OpCodes.Ldsfld, fi); 
     } 
     else 
     { 
      throw new ArgumentException(nameof(expression)); 
     } 

     il.Emit(OpCodes.Ldstr, method.Name); 
     il.Emit(OpCodes.Ldc_I4_0); 
     il.Emit(OpCodes.Callvirt, invoke); 
     il.Emit(OpCodes.Ret); 

     return method.CreateDelegate(typeof(TestDelegate)) as TType; 
    } 
} 

public class Program 
{ 
    public static void Main(string[] args) 
    { 
     ExampleTwo 
      .CreateDelegate<TestDelegate>(() => ExampleOne.OnFunctionCall) 
      .Invoke(); 

     ExampleTwo 
      .CreateDelegate<TestDelegate>(() => ExampleOne.OnFunctionCallField) 
      .Invoke(); 

     Console.ReadLine(); 
    } 
} 

的代码.Net的核心2.0上运行。

相关问题