2009-12-13 16 views
12

Sto leggendo e imparando a riflettere in C#. Sarebbe bello sapere come può aiutarmi nel mio lavoro quotidiano, quindi voglio che le persone con più esperienza di me mi diano esempi o idee su quali tipi di cose possiamo ottenere usandolo, o come possiamo ridurre la quantità di codice che scriviamoRiflessione. Cosa possiamo ottenere usando?

Grazie.

+1

domanda correlata: http://stackoverflow.com/questions/1859902/in-3-minutes-what-is-reflection –

+1

correlati sì, ma personalmente penso che la domanda è piuttosto scortese. L'integrazione è la derivazione inversa è calcolo, ma scommetto che ti dico che ti ha insegnato quasi nulla, anche se sai che cos'è la derivazione. : D –

risposta

10

Recentemente ho usato per aggiungere attributi personalizzati ai campi nel mio enum:

public enum ShapeName 
{ 
    // Lines 
    [ShapeDescription(ShapeType.Line, "Horizontal Scroll Distance", "The horizontal distance to scroll the browser in order to center the game.")] 
    HorizontalScrollBar, 
    [ShapeDescription(ShapeType.Line, "Vertical Scroll Distance", "The vertical distance to scroll the browser in order to center the game.")] 
    VerticalScrollBar, 
} 

utilizzando la riflessione per ottenere il campo:

public static ShapeDescriptionAttribute GetShapeDescription(this ShapeName shapeName) 
    { 
     Type type = shapeName.GetType(); 
     FieldInfo fieldInfo = type.GetField(shapeName.ToString()); 
     ShapeDescriptionAttribute[] attribs = fieldInfo.GetCustomAttributes(typeof(ShapeDescriptionAttribute), false) as ShapeDescriptionAttribute[]; 

     return (attribs != null && attribs.Length > 0) ? attribs[0] : new ShapeDescriptionAttribute(ShapeType.NotSet, shapeName.ToString()); 
    } 

La classe di attributo:

[AttributeUsage(AttributeTargets.Field)] 
public class ShapeDescriptionAttribute: Attribute 
{ 
    #region Constructor 
    public ShapeDescriptionAttribute(ShapeType shapeType, string name) : this(shapeType, name, name) { } 

    public ShapeDescriptionAttribute(ShapeType shapeType, string name, string description) 
    { 
     Description = description; 
     Name = name; 
     Type = shapeType; 
    } 
    #endregion 

    #region Public Properties 
    public string Description { get; protected set; } 

    public string Name { get; protected set; } 

    public ShapeType Type { get; protected set; } 
    #endregion 
} 
9

In generale, Reflection ti consente di accedere ai metadati relativi agli oggetti. Combinare la riflessione con altre tecniche ti consente di rendere il tuo programma più dinamico. Ad esempio è possibile caricare una DLL e determinare se contiene un'implementazione di un'interfaccia. Si può usare questo per scoprire la funzionalità di supporto di dll in fase di runtime. L'uso potrebbe utilizzare questo per estendere un'applicazione senza una ricompilazione e senza doverla riavviare.

Intellisense in Visual Studio utilizza la riflessione per fornire informazioni sugli oggetti che si stanno utilizzando.

Si noti che l'uso di Reflection ha un costo. Riflettere un oggetto può essere lento. Ma se ne hai bisogno, Reflection è uno strumento molto utile.

+1

È possibile mitigare tali costi in vari modi; il codice basato sulla riflessione può essere veloce quanto il codice normale. –

0

Ho usato solo la riflessione nel codice di produzione una volta. Era una situazione in cui dovevo apportare modifiche a cosa - fino a quel momento nel tempo - era stato l'uso standardizzato di un particolare metodo di classe in una routine di avvio (mi spiace non essere più specfico - era un po 'di tempo fa e i dettagli sono nebbioso). L'unico modo per aggirare il problema era quello di introdurre una versione diversa del metodo ed esaminare vari criteri/condizioni del codice ecc. In fase di esecuzione per determinare quale metodo dovrei chiamare. Si trattava di un pezzo di codice piuttosto compatto che forniva una succinta soluzione a quello che altrimenti sarebbe stato un problema disordinato da risolvere.

0

Qui ci sono alcune cose che ho usato per la riflessione che sarebbe estremamente difficile o impossibile senza di essa:

  • mio C# porto del motore StringTemplate template. La riflessione viene utilizzata per riattivare le proprietà degli oggetti dinamici.
  • Un compilatore CLI JIT scritto in codice gestito.

Il Managed Extensibility Framework (una nuova libreria .NET) utilizza la reflection per:

  • Individuare e comporre le parti, comprese le importazioni che si applicano.
  • Evita il caricamento degli assembly per l'esecuzione fino a quando il loro contenuto non è richiesto.
2

Un uso tra molti: è possibile creare un'architettura plug-in in cui si specifica il nome della classe da utilizzare in un file di configurazione. Usando il reflection puoi prendere questa stringa e creare un'istanza dell'oggetto richiesto. Se quell'oggetto implementa un'interfaccia conosciuta, allora puoi usarla attraverso il codice ordinario (non di riflessione).

1

Ho usato la riflessione per consentirmi una maggiore flessibilità in risposta ai requisiti in costante evoluzione. Cioè, il cliente continuava a cambiare idea su dove collocare una tabella di database all'interno di un database. Tutto ciò che ho fatto è stato che l'oggetto controllasse i suoi campi e chiamasse i costruttori oggetto di quei campi all'interno dell'oggetto stesso. Quindi, se un tavolo dovrebbe essere trovato da qualche altra parte? Clicca, incolla, fatto.

Questo non è andato in produzione finale, si badi bene, ma durante la fase iterativa è stato rimosso un po 'del boilerplate che avrei dovuto cambiare.

1

Ho usato il riflesso per facilitare la traduzione di controlli come etichette e pulsanti sulle nostre forme. Usando il reflection, passerei attraverso tutti i controlli del mio modulo e scriverò il nome, il testo e il titolo dei controlli in un file XML. Dopo che i controlli, titolo e testo, sono stati tradotti nell'XML, il file viene riletto nell'impostazione del titolo e del testo di ogni controllo trovato nell'XML ai valori tradotti.
Le nostre forme devono essere tradotte in diverse lingue e l'uso della riflessione ci ha aiutato a risparmiare molto tempo.

-1

Un uso classico che ho per l'utilizzo di Red Gate .Net Reflector per comprendere meglio la meccanica del framework .Net stesso. Vi siete mai chiesti come o perché un oggetto framework in particolare funziona nel modo in cui funziona o siete mai stati un po 'perplessi anche perché qualcosa non funziona nel modo in cui pensavate che sarebbe successo?

A volte la documentazione può essere un po 'squallida a dir poco, ma utilizzando la riflessione e lo strumento di Redgate puoi annusare nel codice framework per capire meglio il come/perché/che dire di tutto.

Più di alcuni bug sono stati trovati nel codice CLR tramite "MS outsiders" utilizzando la reflection.

+1

Avrei bisogno di controllare, ma non sono sicuro che Reflector usi il riflesso come tale; Ho avuto l'impressione di leggere e analizzare l'IL direttamente, piuttosto che usare l'API di reflection. –

3

È un valore inestimabile per il codice di libreria che non ha bisogno di sapere sul chiamante, come con i generici, ma con un accesso più ricco ai dati. Esempi:

  • ORM (materializzazione ecc)
  • serializzazione/deserializzazione
  • oggetto clonazione/copia completa
  • UI/codice vincolante (rigorosamente questo è ComponentModel, ma è possibile mescolare i due - per esempio, HyperDescriptor)

Si dovrebbe ovviamente provare a ridurre al minimo la quantità di riflessione che si fa, ma è possibile attenuare il costo memorizzando nella cache i delegati da om Delegate.CreateDelegate/Expression/DynamicMethod

1

la finestra delle proprietà di VS è basato riflessione - se si effettua un controllo utente è possibile modificare le proprietà su di essa dal PropertyGrid (sua anche un controllo è possibile utilizzare se si vuole) immediatamente. Naturalmente è possibile aggiungere attributi per migliorare il modo in cui viene visualizzato (a cui si accede tramite riflessione).

L'ho utilizzato anche per implementare una classe di serializzazione binaria personalizzata.

Qui ho una classe in cui utilizzo il reflection per serializzare/deserializzare e fornire attributi per ulteriori informazioni sull'interfaccia utente.

[TypeConverter(typeof(IndexedExpandableObjectConverter))] 
[BinarySerializeable] 
public sealed class Socket 
{ 
    #region Fields (7)  

    [SerializedPosition(0)] 
    Byte _mode = 1; 

    ... 

    [SerializedPositionAttribute(4)] 
    UInt16 _localPort; 

    ... 

Proprietà #Region (5)

[DisplayName("Listning Port")] 
    [Description("The port which the socket will listen for connections on")] 
    [DisplayIndex (0)] 
    public UInt16 LocalPort 
    { 
     get { return _localPort; } 
     set { _localPort = value; } 
    } 

    ... 

E la funzione di serializzazione - come si può vedere, ci vuole solo un oggetto e l'ordine dei byte (endian) che si desidera. Tutto il resto è determinato dalla riflessione. L'impostazione predefinita SerializationProvider funziona utilizzando gli attributi SerializedPosition sui campi all'interno dell'oggetto (privato o meno).

public static Byte[] Serialize(Object obj, ByteOrder streamOrder) 
{ 

    var provider = GetProvider(obj); 

    if (provider.CanSerialize(obj.GetType())) 
     return provider.Serialize(obj, streamOrder); 

    throw new ArgumentException(obj.GetType() + " is non-serialisable by the specified provider '" + provider.GetType().FullName + "'."); 
} 


private static IBinarySerializatoinProvider GetProvider(Object obj) 
{ 

    var providerAttrib = Reflector.GetAttribute<BinarySerializationProviderAttribute>(obj); 

    if (providerAttrib != null) 
     return CreateProvider(providerAttrib.ProviderType); 

    return CreateProvider(typeof(SerializationProvider)); 
} 
0

immagino che un "stand alone" di applicazione, dove ogni oggetto si utilizza è noto al momento della compilazione , non si utilizza riflessione molto.

Ma quando si scrive una libreria o un codice framework che dovrebbe utilizzare oggetti non noti (completamente - si potrebbe sapere su interfacce o baseclass) in fase di compilazione, la riflessione potrebbe essere preziosa per lavorare con quegli oggetti.

1

Questo è il modo di eseguire metodi basati su un enum o una stringa magica ...


    public enum ReflectionTestMethods 
    { 
     MethodA, 
     MethodB, 
     MethodC 
    } 
    public class ReflectionTest 
    { 

     public void Execute(ReflectionTestMethods method) 
     { 
      MethodInfo methodInfo = GetType().GetMethod(method.ToString() 
       , BindingFlags.Instance | BindingFlags.NonPublic); 
      if (methodInfo == null) throw new NotImplementedException(method.ToString()); 
      methodInfo.Invoke(this, null); 
     } 

     private void MethodA() 
     { 
      Debug.Print("MethodA"); 
     } 

     private void MethodB() 
     { 
      Debug.Print("MethodB"); 
     } 

     private void MethodC() 
     { 
      Debug.Print("MethodC"); 
     } 
    } 

Ma questa è forse una soluzione migliore ...


    public class ActionTest 
    { 
     private readonly Dictionary _actions = new Dictionary(); 

     public ActionTest() 
     { 
      _actions.Add(ReflectionTestMethods.MethodA.ToString(), new Action(MethodA)); 
      _actions.Add(ReflectionTestMethods.MethodB.ToString(), new Action(MethodB)); 
      _actions.Add(ReflectionTestMethods.MethodC.ToString(), new Action(MethodC)); 
     } 

     public void Execute(ReflectionTestMethods method) 
     { 
      if (!_actions.ContainsKey(method.ToString())) 
       throw new NotImplementedException(method.ToString()); 
      _actions[method.ToString()](); 
     } 

     private void MethodA() 
     { 
      Debug.Print("MethodA"); 
     } 

     private void MethodB() 
     { 
      Debug.Print("MethodB"); 
     } 
     private void MethodC() 
     { 
      Debug.Print("MethodC"); 
     } 
    } 
0

Io lo uso per: iniezione

  • Dipendenza
  • Soluzioni alternative per la mancanza di Microsofts motivazione per aggiungere cose come "covariant/contravariant generico" e "new() i vincoli con parametri"
  • Aspect Oriented Programming (in una certa misura, per lo più io uso PostSharp)
0

riflessioni sono bello per "tardiva" soluzioni in cui non desideri avere un riferimento fisico collegato al tuo progetto ma piuttosto "connetterlo" in un secondo momento. In questo modo se il riferimento non è presente e non è critico, non ottieni errori non manuali di riferimenti mancanti. Hai un errore controllato che puoi gestire.

Problemi correlati