2017-08-20 4 views
2

Dans cet exemple de code, j'essaie d'invoquer une action anonyme de la part d'un générateur. Je ne suis pas sûr si et comment je peux charger la référence au délégué et comment l'appeler. Je peux le faire si le OnFunctionCall est une méthode statique et non une propriété.Comment appeler Action <chaîne, booléenne> à partir d'un générateur

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

Il est un diable de beaucoup plus facile à utiliser que CodeDOM Émettre – MickyD

+0

@MickyD Reflection Pouvez-vous donner un exemple – ptp

+0

@MickyD Il doit être compatible avec la norme 2.0 trop nette – ptp

Répondre

2

Vous devez transmettre les informations où le délégué que vous voulez appeler est stocké. La commodité est d'accepter un MemberExpression, sinon accepter un MemberInfo fonctionnerait aussi. Jetez un oeil à votre code modifié:

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

Le code fonctionne sur .Net Core 2.0.