2013-06-10 8 views
7

Ho visto domande/risposte simili per questo postate in passato, ma le mie differiscono leggermente dalle altre che ho visto.Selezione dinamica del metodo in base al tipo di parametro runtime

In sostanza, ho un'interfaccia comune e diverse classi che implementano/ereditano da esso. Quindi, in una classe separata, ho metodi che devono agire sugli oggetti dati dall'interfaccia IObject. Tuttavia, ognuno di essi deve essere interpretato in modi diversi, quindi perché esiste una dichiarazione separata del metodo per ogni tipo concreto che estende IObject.

class IObject 
{ 
    ... 
} 

class ObjectType1 : IObject 
{ 
    ... 
} 

class ObjectType2 : IObject 
{ 
    ... 
} 

class FooBar 
{ 
    void Foo (ObjectType1 obj); 
    void Foo (ObjectType2 obj); 
} 

Ora, per me, una soluzione ovvia è quello di approfittare di binding dinamico posizionando il metodo Foo all'interno di ogni singola classe, che avrebbe scelto automaticamente in fase di esecuzione e la correttezza Foo da eseguire. Tuttavia, questo è non un'opzione qui, perché sto definendo più modelli su come agire su questi oggetti, e preferisco incapsulare ogni singolo modello per gestire gli oggetti nella sua stessa classe, piuttosto che inserire tutti i modelli nel classi di oggetti.

Ho trovato il post this che mostra come utilizzare un dizionario per scegliere dinamicamente in fase di esecuzione l'implementazione del metodo corretto. Sto bene con questo approccio; tuttavia, supponiamo di dover eseguire una spedizione come questa una volta in ogni modello. Se ho solo IObject e le sue implementazioni concrete, c'è un modo per generalizzare questo approccio in modo da poter chiamare i metodi di qualsiasi nome in base al tipo di runtime degli oggetti?

So che questa è probabilmente una domanda poco chiara, ma apprezzerei molto qualsiasi aiuto.

risposta

10

Il dynamic parola chiave è in realtà molto bravo in questo:

void Main() 
{ 
    var foobar = new FooBar(); 
    foreach(IObject obj in new IObject[]{ new ObjectType1(), new ObjectType2()}) 
    { 
     foobar.Foo((dynamic)obj); 
    } 
    // Output: 
    // Type 1 
    // Type 2 
} 

class IObject 
{ 
} 

class ObjectType1 : IObject 
{ 
} 

class ObjectType2 : IObject 
{ 
} 

class FooBar 
{ 
    public void Foo (ObjectType1 obj) { 
     Console.WriteLine("Type 1"); 
    } 
    public void Foo (ObjectType2 obj) { 
     Console.WriteLine("Type 2"); 
    } 
} 

Il codice è super-semplice, ed è ottenuto pretty decent performance.

+0

Questa è la risposta giusta, penso. – Ziffusion

+1

Oh wow, se questo si comporta come sembra, allora è magnifico! Mi divertirò un po 'quando avrò qualche possibilità, ma grazie per questa soluzione. L'attenzione nel mio codice è sulla leggibilità e manutenzione facile, quindi questo sembra piuttosto sorprendente. – TSM

2

Forse vuoi qualcosa di molto vicino a visitor patter.

Se si desidera solo di scegliere un metodo (Foo) di un oggetto (FooBar) dal tipo di argomento è possibile utilizzare la reflection per ottenere tutti i metodi con nome dato (Foo) e corrispondono manuale del ragionamento in base al tipo di oggetto (ObjectTypeX) e le scelte dell'argomento. Non dimenticare di gestire correttamente le classi derivate.

Per evitare di pagare il costo della riflessione su ogni chiamata - risultati della cache (ad esempio compilando/compilando it Albero delle espressioni).

Nota che l'approccio Dizionario (azioni per un determinato metodo indicizzato per tipo) sarà probabilmente più semplice da supportare/debug per iniziare. Più tardi, se lo trovi lento per te, puoi sostituirlo con qualcosa di più complicato come il riflesso.

+0

Interessante, grazie per il feedback!Conosco leggermente il Visitor Design Pattern, ma sono molto nuovo in C# e sto solo esplorando tutte le mie opzioni. – TSM

0

si può solo fare un metodo che accetta il tipo di interfaccia, poi si controlla per il correcttype e lo gettò

ObjectType1 obj1 = new ObjectType1(); 

foo(obj1); 

void foo(IObject fm) 
     { 
      ObjectType1 cls; 
      if (fm is ObjectType1) 
      { 
       cls = fm as ObjectType1; 
       cls.ID = 10; 
       MessageBox.Show(cls.ID.ToString() + " " + cls.GetType().ToString()); 
      } 
     } 

questo è perché le classi implementano IObject , cls.ID è solo un esempio è possibile metti una proprietà che implementa. Si prega di provare e fammi sapere .... i migliori auguri.

+0

Questo è stato l'approccio preso alcuni giorni prima (perché ho familiarità con esso e avevo bisogno di una demo funzionante). Ora che sto affrontando questo problema su una scala più ampia, sto esplorando altre opzioni più semplici che potrebbero essere specifiche per C#. Questo approccio funziona, però! – TSM

Problemi correlati