Chiamare un metodo generico con un argomento di tipo noto solo al momento dell’esecuzione

Modificare:

Ovviamente il mio vero codice non sembra esattamente così. Ho provato a scrivere codice semi-pseudo per rendere più chiaro di cosa volessi fare.

Sembra che abbia semplicemente incasinato le cose.

Quindi, quello che in realtà vorrei fare è questo:

Method(); Method(); Method(); ... 

Beh … ho pensato che forse avrei potuto trasformarlo in un loop usando il riflesso. Quindi la domanda è: come faccio? Ho una conoscenza molto superficiale della riflessione. Quindi gli esempi di codice sarebbero grandiosi.

Lo scenario è simile a questo:

 public void Method() where T : class {} public void AnotherMethod() { Assembly assembly = Assembly.GetExecutingAssembly(); var interfaces = from i in assembly.GetTypes() where i.Namespace == "MyNamespace.Interface" // only interfaces stored here select i; foreach(var i in interfaces) { Method(); // Get compile error here! } 


Post originale:

Ciao!

Sto cercando di scorrere tutte le interfacce in un namespace e inviarle come argomenti ad un metodo generico come questo:

 public void Method() where T : class {} public void AnotherMethod() { Assembly assembly = Assembly.GetExecutingAssembly(); var interfaces = from i in assembly.GetTypes() where i.Namespace == "MyNamespace.Interface" // only interfaces stored here select i; foreach(var interface in interfaces) { Method(); // Get compile error here! } } 

L’errore che ottengo è “Nome del tipo previsto, ma il nome della variabile locale è stato trovato”. Se ci provo

 ... foreach(var interface in interfaces) { Method(); // Still get compile error here! } } 

Ricevo “Imansible applicare l’operatore” <"agli operandi di tipo" metodo group "e" System.Type "" Qualche idea su come ovviare a questo problema?

EDIT: Ok, tempo per un programma breve ma completo. La risposta di base è come prima:

  • Trova il metodo generico “aperto” con Type.GetMethod
  • Rendilo generico usando MakeGenericMethod
  • Richiamalo con Invoke

Ecco alcuni esempi di codice. Si noti che ho modificato l’espressione della query in notazione puntata: non è necessario utilizzare un’espressione di query quando in pratica hai appena ottenuto una clausola where.

 using System; using System.Linq; using System.Reflection; namespace Interfaces { interface IFoo {} interface IBar {} interface IBaz {} } public class Test { public static void CallMe() { Console.WriteLine("typeof(T): {0}", typeof(T)); } static void Main() { MethodInfo method = typeof(Test).GetMethod("CallMe"); var types = typeof(Test).Assembly.GetTypes() .Where(t => t.Namespace == "Interfaces"); foreach (Type type in types) { MethodInfo genericMethod = method.MakeGenericMethod(type); genericMethod.Invoke(null, null); // No target, no arguments } } } 

Risposta originale

Lasciamo da parte gli ovvi problemi di chiamare una variabile “interfaccia” per iniziare.

Devi chiamarlo per riflessione. Il punto di generici è di mettere più tipi di controllo in fase di compilazione . Non sai quale sia il tipo al momento della compilazione, quindi devi usare i generici.

Ottieni il metodo generico e chiama MakeGenericMethod su di esso, quindi richiamalo.

Il tuo tipo di interfaccia è effettivamente generico? Chiedo perché stai chiamando MakeGenericType su di esso, ma non passando nessun argomento di tipo … Stai provando a chiamare

 Method>(); // (Or whatever instead of string) 

o

 Method(); 

Se è il secondo, è sufficiente una chiamata a MakeGenericMethod – non MakeGenericType.