2017-08-20 7 views
2

このサンプルコードでは、il generatorから匿名アクションを呼び出そうとしています。私は、デリゲートへの参照とそれを呼び出す方法を読み込むことができるかどうか、また、どのように呼び出すことができるのか分かりません。 OnFunctionCallが静的​​メソッドではないプロパティの場合は、私はそれを行うことができます。il generatorからアクション<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

Reflect EmitよりもCodeDOMを使用したほうが簡単です – MickyD

+0

@MickyD例を提供できます – ptp

+0

@MickyDこれもネット標準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 Core 2.0で動作しています。

関連する問題