2009-04-02 36 views
7

Ho seguenti classi:C# - gettato classe generica alla sua base non generica classe

public abstract class CustomerBase 
{ 
    public long CustomerNumber { get; set; } 
    public string Name { get; set; } 
} 

public abstract class CustomerWithChildern<T> : CustomerBase 
    where T: CustomerBase 
{ 
    public IList<T> Childern { get; private set; } 

    public CustomerWithChildern() 
    { 
     Childern = new List<T>(); 
    } 
} 

public class SalesOffice : CustomerWithChildern<NationalNegotiation> 
{ 
} 

Il SalesOffice è solo uno dei pochi classi che rappresentano diversi livelli gerarchici del cliente. Ora ho bisogno di passare attraverso questa gerarchia da un certo punto (CustomerBase). Non riesco a capire come implementare senza usare la reflection. Mi piacerebbe realizzare qualcosa del tipo:

public void WalkHierarchy(CustomerBase start) 
    { 
     Print(start.CustomerNumber); 
     if (start is CustomerWithChildern<>) 
     { 
      foreach(ch in start.Childern) 
      { 
       WalkHierarchy(ch); 
      } 
     } 
    } 

C'è qualche possibilità che io possa ottenere qualcosa di simile a questo lavoro?


La soluzione basata su suggerita ha-childern interfaccia ho implementato:

public interface ICustomerWithChildern 
{ 
    IEnumerable ChildernEnum { get; } 
} 

public abstract class CustomerWithChildern<T> : CustomerBase, ICustomerWithChildern 
    where T: CustomerBase 
{ 
    public IEnumerable ChildernEnum { get { return Childern; } } 

    public IList<T> Childern { get; private set; } 

    public CustomerWithChildern() 
    { 
     Childern = new List<T>(); 
    } 
} 

    public void WalkHierarchy(CustomerBase start) 
    { 
     var x = start.CustomerNumber; 
     var c = start as ICustomerWithChildern; 
     if (c != null) 
     { 
      foreach(var ch in c.ChildernEnum) 
      { 
       WalkHierarchy((CustomerBase)ch); 
      } 
     } 
    } 

risposta

2

Credo che tu voglia fare la ricerca per la determinazione di fare al walk un'interfaccia.

Quindi magari aggiungere un'interfaccia "IWalkable" che espone le informazioni necessarie per eseguire il walk, quindi è possibile creare il metodo di verifica per vedere se l'oggetto passato implementa l'interfaccia.

2

"è" e "come" funziona solo su tipi generici qualificati.

Vedere this MSDN discussion per dettagli che includono soluzioni alternative.

La soluzione più comune che ho visto è quella di aggiungere un'interfaccia al mix che potrebbe essere implementata da CustomerWithChildren e controllare tale interfaccia.

7

È possibile spostare il metodo WalkHierarchy sulla classe base e renderlo virtuale. L'implementazione della classe base processerebbe solo il nodo corrente. Per la classe CustomerWithChildern<T>, l'override farebbe una camminata reale.

+0

Questa è la soluzione migliore in quanto racchiude in sé l'attuazione piedi e appena fa la cosa giusta senza forzare al chiamante di essere a conoscenza dei dettagli di implementazione. – recursive

+0

Grandi elogi da parte di qualcuno chiamato "ricorsivo". ;-) –

+0

Il mio ultimo grande progetto .NET ha avuto un simile requisito, e il modo di John Saunders è molto simile a quello che ho fatto io. Ha reso molte cose molto più facili :) – OregonGhost

0

Esplicitamente con questo metodo, no. Tuttavia è possibile ottenere la stessa funzionalità con un'interfaccia. In effetti, potresti semplicemente avere la tua classe generica implementare IEnumerable. Vale anche la pena notare che la classe dovrebbe avere anche "dove T: CustomerBase" per garantire la sicurezza del tipo.

1

Penso che tutti abbiano riscontrato questo "problema" quando prima lavoravano con classi generiche.

Il tuo primo problema è suggerito dal fraseggio della tua domanda: un tipo generico aperto NON è la classe base di una chiusa. Non c'è nessuna relazione OO qui, a tutti. La vera classe base è CustomerBase. Un tipo generico "aperto" è come una classe semi-completata; specificando gli argomenti tipo "lo chiude", rendendolo completo.

Mentre si può fare:

Type t = typeof(CustomerWithChildern<>) 

la condizione

typeof(CustomerWithChildern<>).IsAssignableFrom(CustomerWithChildern<Foo>) 

sarà sempre False.

-Oisin

3

Prova questo:

if(start.GetType().GetGenericTypeDefinition() == typeof(CustomerWithChildern<>)) 
Problemi correlati