2016-09-24 2 views
10
public interface IBar { 
} 
public class Bar : IBar { 
} 
public class Bar2 : IBar { 
} 
public interface IFoo { 
    Task<T> Get<T>(T o) where T : IBar; 
} 
public class Foo : IFoo { 
    public async Task<T> Get<T>(T o) where T : IBar { 
    ... 
    } 
} 

Ich kann mit dieser Methode Reflexion dann rufen:Wie eine generische Asynchron-Methode aufrufen Reflexion mit

var method = typeof(IFoo).GetMethod(nameof(IFoo.Get)); 
var generic = method.MakeGenericMethod(bar2.GetType()); 
var task = generic.Invoke(foo, new [] { bar2 }); 

Wie warte ich auf diesen Task? und wie gewinne ich es auf Task<bar2.GetType()>?

+0

Die Antwort ist zu werfen es statt nur Aufgaben mit jedem awaitable Typ arbeitet, da es ein Objekt zurückgibt (siehe @Fabio). Allerdings sollten Sie sicherstellen, dass "Foo" 'IFoo' erbt, andernfalls erhalten Sie eine Ausnahme, weil' foo' (geliefert am 'Invoke') der falsche Typ ist. – joell

+0

Mögliches Duplikat von [Wie kann man auf eine private asynchrone Methode warten, die durch Reflektion in WinRT aufgerufen wird?] (Http://stackoverflow.com/questions/14711585/how-to-await-an-async-private-method-invoked-using-using-) reflection-in-winrt) – Fabio

Antwort

14

Da Task<T> stammt aus Task Sie nur, dass abwarten kann, sobald die Aufgabe abgewartet Sie Reflektion verwenden können sicher die .Result Eigenschaft über Reflexion zuzugreifen.

Sobald Sie das Ergebnis haben, müssen Sie es entweder in einem IBar speichern und die Methoden und Eigenschaften dafür verwenden oder nach dem Testen auf den spezifischen Typ umwandeln, um die typspezifischen Methoden zu verwenden.

Hier eine vollständige MCVE davon ist

using System; 
using System.Reflection; 
using System.Threading.Tasks; 

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Test().Wait(); 
      Console.ReadLine(); 
     } 

     static async Task Test() 
     { 
      var foo = new Foo(); 
      var bar2 = new Bar2(); 

      object resultObject = await CallGetByReflection(foo, bar2); 

      IBar result = (IBar)resultObject; 
      result.WriteOut(); 

      //or 

      if (resultObject is Bar) 
      { 
       ((Bar)resultObject).Something(); 
      } 
      else if (resultObject is Bar2) 
      { 
       ((Bar2)resultObject).SomethingElse(); 
      } 
     } 

     private static async Task<object> CallGetByReflection(IFoo foo, IBar bar) 
     { 
      var method = typeof(IFoo).GetMethod(nameof(IFoo.Get)); 
      var generic = method.MakeGenericMethod(bar.GetType()); 
      var task = (Task) generic.Invoke(foo, new[] {bar}); 

      await task.ConfigureAwait(false); 

      var resultProperty = task.GetType().GetProperty("Result"); 
      return resultProperty.GetValue(task); 
     } 

     public interface IBar 
     { 
      void WriteOut(); 
     } 
     public class Bar : IBar 
     { 
      public void Something() 
      { 
       Console.WriteLine("Something"); 
      } 
      public void WriteOut() 
      { 
       Console.WriteLine(nameof(Bar)); 
      } 
     } 
     public class Bar2 : IBar 
     { 
      public void SomethingElse() 
      { 
       Console.WriteLine("SomethingElse"); 
      } 
      public void WriteOut() 
      { 
       Console.WriteLine(nameof(Bar2)); 
      } 
     } 
     public interface IFoo 
     { 
      Task<T> Get<T>(T o) where T : IBar; 
     } 
     public class Foo : IFoo 
     { 
      public async Task<T> Get<T>(T o) where T : IBar 
      { 
       await Task.Delay(100); 
       return o; 
      } 
     } 
    } 
} 

UPDATE: Hier ist eine Erweiterung Methode den Prozess

public static class ExtensionMethods 
{ 
    public static async Task<object> InvokeAsync(this MethodInfo @this, object obj, params object[] parameters) 
    { 
     var task = (Task)@this.Invoke(obj, parameters); 
     await task.ConfigureAwait(false); 
     var resultProperty = task.GetType().GetProperty("Result"); 
     return resultProperty.GetValue(task); 
    } 
} 

Das macht CallGetByReflection um

private static Task<object> CallGetByReflection(IFoo foo, IBar bar) 
{ 
    var method = typeof(IFoo).GetMethod(nameof(IFoo.Get)); 
    var generic = method.MakeGenericMethod(bar.GetType()); 
    return generic.InvokeAsync(foo, new[] {bar}); 
} 
zu vereinfachen

UPDATE 2: Hier ist eine neue Erweiterung Methode ist, die mit dynamic und GetAwaiter()

public static class ExtensionMethods 
{ 
    public static async Task<object> InvokeAsync(this MethodInfo @this, object obj, params object[] parameters) 
    { 
     dynamic awaitable = @this.Invoke(obj, parameters); 
     await awaitable; 
     return awaitable.GetAwaiter().GetResult(); 
    } 
} 
1

Basierend auf Ihrem Beispiel wissen Sie Typ zurückgegebene Objekt bei der Kompilierung ->IFoo, so dass Sie normale Guss (IFoo)

var method = typeof(IFoo).GetMethod(nameof(IFoo.Get)); 
var generic = method.MakeGenericMethod(typeof(IBar)); 
var task = (Task<IBar>)generic.Invoke(foo, new [] { bar2 }); 

IBar result = await task; 

verwenden können, wenn Sie nicht über einen Typ zum Zeitpunkt der Kompilierung kennen, dann verwenden Sie einfach dynamic Stichwort

var method = typeof(IFoo).GetMethod(nameof(IFoo.Get)); 
var generic = method.MakeGenericMethod(bar2.GetType()); 
dynamic task = generic.Invoke(foo, new [] { bar2 }); 

IBar result = await task; 

Aber wenn Art der Aufgabe kein Task<iFoo> zur Laufzeit - Ausnahme
geworfen werden Und wenn Sie konkret benötigen Typ IBar dann

var concreteResult = Convert.ChangeType(result, bar2.GetType()); 
+0

'var task = (Aufgabe ) generic.Invoke (foo, neu [] {bar2});' throws 'InvalidCastException' Kann das Objekt vom Typ' 'System.Threading.Tasks.Task nicht umwandeln ''type' 'System.Threading.Tasks.Task '' – user2321864

+0

'dynamische Aufgabe = generic.Invoke (foo, new [] {bar2}); IBar Ergebnis = warten Aufgabe; 'gibt immer' null' zurück – user2321864

+1

@ user2321864 statt 'method.MakeGenericMethod (bar2.GetType());' Sie tun müssen 'Methode.MakeGenericMethod (typeof (IBar)); 'dann wird das erste Beispiel funktionieren. 'Task ' ist nicht kovariant, so können Sie nicht 'Task ' zu 'Task ' –

Verwandte Themen