Domanda

In primo luogo, una piccola introduzione.

Devo funzioni:

static class C
{
  static void F1(Type type)
  {
    // Do something to invoke F2<T>
  }
  static void F2<T>()
  {
    // bla bla bla
  }
}

desidero invocare F1(Type), che a sua volta dovrebbe passare al contesto generica pertinente al parametro di tipo data e richiamare il F2<T> controparte generico.

Un'implementazione ingenuo sarebbe una riflessione semplice, come questo (tralascio bandiere per la chiarezza vincolante):

void F1(Type type)
{
  var f2MethodInfo = typeof(C).GetMethod("F2").MakeGenericMethod(type);
  f2MethodInfo.Invoke(null, new object[0]);
}

Un'implementazione più avanzata sarebbe memorizzare informazioni metodo aperto di F2 - typeof(C).GetMethod("F2") a parte, ma ancora è fondamentalmente la stessa cosa

.

Se F1 viene richiamato molte volte e vogliamo migliorare le prestazioni, allora la soluzione standard "sul mercato" si avvale di un metodo di dizionario e Delegate.CreateDelegate, in questo modo:

IDictionary<Type, Action> m_cache = new Dictionary<Type, Action>();
MethodInfo F2MethodInfo = typeof(C).GetMethod("F2");
void F1(Type type)
{
  Action action;
  if (!m_cache.TryGetValue(type, out action))
  {
    m_cache[type] = action = (Action)Delegate.CreateDelegate(typeof(Action), F2MethodInfo.MakeGenericMethod(type));
  }
  action();
}

E ora alla mia domanda. E 'possibile eliminare completamente il dizionario?

Per esempio, attraverso l'emissione di una certa funzione di fantasia con Reflection.Emit che avrebbe ricevuto un'istanza Tipo e F2MethodInfo e rendere la transizione dentro senza e dizionari? Questa funzione fantasia deve essere emessa solo una volta e funziona per qualsiasi tipo. Mi chiedo se qualsiasi tipo di cache di tipo di mappatura ai delegati può essere eliminata in questo modo.

Grazie.

Modifica

Per il bene di questa discussione, supponiamo che la funzione di fantasia emessa sa che dovrebbe richiamare F2, il che significa che non ha bisogno di ricevere il suo informazioni metodo. E 'possibile fosso dizionario allora?

È stato utile?

Soluzione

  

E 'possibile effettuare il passaggio da (Type) F a F senza riflettere e senza un dizionario?

No, MakeGenericType è l'approccio giusto.

Si parla emettendo una funzione di fantasia per fare questo; che la funzione di fantasia sarà ancora bisogno di finire con un'istruzione call, e che richiede un MethodInfo nello stesso modo in cui Delegate.CreateDelegate fa.

Si potrebbe generare il codice in anticipo per un insieme di tipi conosciuti, magari usando Reflection.Emit, o CodeDom, o anche la generazione di codice a tempo di compilazione. Ma credo che se tu sapessi i tipi in anticipo, devi già essere approfittando di quella nel vostro approccio dizionario, giusto?

Altri suggerimenti

Pensare di esso, la mia impressione è che non si otterrà liberarsi del dizionario, se si desidera mantenere le cose efficiente. È possibile liberarsi della riflessione Invoke emettendo IL (sia via LGC, Reflection.Emit o Expression Tree), ma avrai ancora per creare uno stub per ogni tipo da utilizzare.

Credo che mi piacerebbe andare con LCG e conservare i delegati in un dizionario.

Quando è richiamare molte volte, quindi non richiamare più volte (Type) F, ma piuttosto cambiarlo in una fabbrica che restituirà un delegato del tipo di azione.

Ora si può fare quello che vuoi con esso.

readonly IDictionary<Type, Action> _BlablasByType = new Dictionary<Type, Action>();
readonly MethodInfo _F2MethodInfo = typeof(C).GetMethod("F2");
void GetBlablaFor(Type type)
{
  Action action;
  if (! _BlablasByType.TryGetValue(type, out action))
  {
    _BlablasByType.Add(type, 
                       action = (Action)Delegate.CreateDelegate(typeof(Action),                                                                                                                                        
                                                                _F2MethodInfo.MakeGenericMethod(type));
  }
  return action;
}

var blabla = GetBlablaFor(typeof(Abc));
for(int i = 0; i < 10000; i++)
  blabla();

Farlo nella direzione opposta:

static void F1(Type type) {
    // do stuff
}

static void F2<T>() {
    F1(typeof(T))
}

No riflettere-y nonsense, ed è davvero lo stesso contesto, a meno che non si dispone di ulteriori requisiti che non ci hai raccontato.

Il sistema di Java funziona meglio per questo:

static <T> void F1(Class<T> clazz) {
    // do stuff
}

Hai sia l'oggetto di contesto e di tipo generico.

Non è possibile. E 'possibile preparare il delegato / interfaccia per includerlo come strategia nella progettazione, e tenere riflessione solo nel tempo di inizializzazione.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top