2010-11-19 3 views
5

C'è sizeof() e typeof(), ma perché non un memberinfo() restituisce un'istanza di System.Reflection.MemberInfo per la parte di codice selezionata per facilitare il codice di riflessione.Perché non una funzione reflection memberinfo() per C#

Esempio:

Program() 
{ 
     Type t = typeof(Foo); 

     Foo foo = new Foo(); 
     PropertyInfo pi = memberinfo(Foo.Name) as PropertyInfo; 
     // or shall it be like this 
     // PropertyInfo pi = memberinfo(foo.Name) as PropertyInfo; 

     string name = pi.GetValue(foo, null); 
} 

Sto cercando di capire se c'è una ragione fondamentale per cui questo potrebbe essere implementato in C# spec.

Non sto colpendo nulla, sto solo facendo un pio desiderio, quindi sii gentile per favore.

+0

Potrebbe probabilmente essere implementato facilmente. Anch'io volevo qualcosa di simile. Si noti che sarebbe necessaria una sintassi alternativa per i metodi, poiché possono essere sovraccaricati, quindi specificare il nome da solo non sarebbe sufficiente in quel caso. – cdhowie

+0

È possibile creare qualcosa di simile usando Expression Trees; questo funziona particolarmente bene per proprietà e campi. –

+0

@Bryant hai un esempio o un link? – ja72

risposta

8

Eric Lippert parla di questo ampiamente sul suo blog

Per citare direttamente da questo messaggio:

Appena fuori dalla parte superiore della mia testa, ecco alcuni {ragioni per cui questo non è stato fatto}. (1) Come si specifica in modo univoco che si desidera un'informazione di metodo di un'implementazione specifica dell'interfaccia esplicita? (2) Cosa accadrebbe se la risoluzione di sovraccarico avesse saltato un particolare metodo perché non era accessibile? È legale ottenere informazioni sui metodi che non sono accessibili; i metadati sono sempre pubblici anche se descrivono dettagli privati. Dovremmo rendere impossibile ottenere metadati privati, rendere debole la funzione, o dovremmo renderla possibile, e rendere infoof utilizzare un algoritmo di risoluzione del sovraccarico leggermente diverso rispetto al resto di C#? (3) Come si specifica che si desidera l'informazione di, ad esempio, un setter dell'indicizzatore, o un getter di proprietà, o un sommatore di un gestore di eventi?

5

Ci sono un paio di elementi che rendono difficile questo tipo di funzionalità. Uno dei principali è il sovraccarico dei metodi.

class Example { 
    public void Method() {} 
    public void Method(int p1) {} 
} 

Quali MethodInfo sarebbe il seguente ritorno?

var info = memberinfo(Example.Method); 

Come Wesley ha sottolineato, però, ha il pieno Eric's Blog discussione su questo tema.

+1

Il tuo esempio è un po 'off, dal momento che 'Type.GetMethod()' non funzionerebbe in questo caso ... getta un 'AmbiguousMatchException'. Sebbene esistano sfide sintattiche per implementare 'infoof', renderebbe sicuramente il codice sensibile alla riflessione un po 'più gestibile. Se 'infoof' è sufficientemente prezioso rispetto a tutti gli altri possibili miglioramenti del linguaggio C# è un'altra questione interamente. – LBushkin

+0

Potrebbe restituire un array con tutti i sovraccarichi. – ja72

+0

@LBushkin non sono sicuro di come questo offra il mio esempio. Sottolinea le difficoltà nel disambiguare i metodi sovraccaricati con l'ipotetica feature memberinfo. – JaredPar

1

Ci sono numerose ragioni per cui membro riflessione a tempo di compilazione non è ancora stato implementato in C# - ma la maggior parte di loro in sostanza si riducono a opportunity cost - ci sono molte caratteristiche altre lingue e miglioramenti che offrono più benefici a più utenti. C'è anche la considerazione che una sintassi infoof potrebbe essere complicata, confusa e, in definitiva, meno potente dell'uso della riflessione basata su stringhe. Inoltre, non sarebbe una sostituzione completa per la riflessione poiché in molti casi i metadati manipolati non sono noti al momento della compilazione.

Tuttavia, non tutto è perduto, ci sono una serie di trucchi che è possibile utilizzare per eseguire una riflessione leggermente più sicura che sfrutta le funzionalità del linguaggio C#. Ad esempio, possiamo sfruttare le espressioni lambda e gli alberi di espressione per estrarre informazioni su MemberInfo.Un semplice esempio è:

public static class MethodExt { 
    static MethodInfo MemberInfo(Action d) { 
     return d.Method; 
    } 
    // other overloads ... 
} 

che funziona quando si passa in un (non anonima) azione delegato:

MethodInfo mi = MethodExt.MemberInfo(Object.ToString); 

Un'implementazione del sopra utilizzando alberi espressione può più robusto e flessibile, ma anche sostanzialmente più complicato. Può essere utilizzato per rappresentare accesso a membri e proprietà, indicizzatori, ecc.

Il problema principale con tutti questi approcci "fantasiosi" è che essi confondono gli sviluppatori che sono abituati a vedere il codice di riflessione tradizionale. Inoltre, non sono in grado di gestire tutti i casi, il che spesso si traduce in una sfortunata combinazione di codice di riflessione tradizionale e codice dell'albero delle espressioni di fantasia. Personalmente, mentre queste tecniche sono interessanti e inventive, è probabilmente meglio evitarle nel codice di produzione.

+0

'D' afferma di avere una riflessione del tempo di compilazione! :) – nawfal

0

Io stesso utilizzo un approccio che legge l'IL da un metodo anonimo (utilizzando lo spazio dei nomi Mono.Reflection) e acquisisce le informazioni dell'ultimo token trovato nel metodo anonimo. Questo tende ad essere l'unico modo per ottenere informazioni su cose come il add_EventHandler o set_Property o variabili locali catturate. Per ottenere proprietà reali uso alberi di espressione.

La sintassi che utilizzo è Reflect.Member<T>.InfoOf<TMember>(Func<T,TMember> memberfunc) dove Member viene sostituito con il tipo a cui sono interessato. È verbose sicuro, ma consente a un utente di sapere esattamente cosa sta tentando di fare il codice. Ho anche stili Reflect.Member per cose come statica e costruttori. Ecco il frammento di codice relativo ::

internal static MemberInfo GetLastMemberOfType(MethodBase method, MemberTypes memberType) 
    { 
     var instructions = method.GetInstructions(); 
     var operandtype = memberType == MemberTypes.Field ? OperandType.InlineField : OperandType.InlineMethod; 
     for (int i = instructions.Count-1; i > -1 ; i--) 
     { 
      if (instructions[i].OpCode.OperandType == operandtype) 
      { 
       return instructions[i].Operand as MemberInfo; 
      } 
     } 
     return null; 
    } 

vuol sostituire riflessione basata stringa? Assolutamente no. Rende il mio codice più sicuro mentre eseguo il refactoring delle interfacce e cosa no? Assolutamente. Sarà spedito con il prodotto su cui sto lavorando? Probabilmente no.

Problemi correlati