2009-12-01 10 views
5

Sto lavorando su un motore di gioco in C#. La classe a cui sto lavorando si chiama CEntityRegistry e il suo compito è quello di tenere traccia delle numerose istanze di CEntity nel gioco. Il mio obiettivo è poter interrogare lo CEntityRegistry con un determinato tipo e ottenere un elenco di ogni CEntity di quel tipo.Dato un tipo C#, Ottieni le sue classi di base e le interfacce implementate

Quello che mi piacerebbe fare, quindi, è di mantenere una mappa:

private IDictionary<Type, HashSet<CEntity>> m_TypeToEntitySet; 

E aggiornare il Registro di questa convenzione:

private void m_UpdateEntityList() 
     { 
      foreach (CEntity theEntity in m_EntitiesToRemove.dequeueAll()) 
      { 
       foreach (HashSet<CEntity> set in m_TypeToEntitySet.Values) 
       { 
        if (set.Contains(theEntity)) 
         set.Remove(theEntity); 
       } 
      } 
      foreach (CEntity theEntity in m_EntitiesToAdd.dequeueAll()) 
      { 
       Type entityType = theEntity.GetType(); 
       foreach (Type baseClass in entityType.GetAllBaseClassesAndInterfaces()) 
        m_TypeToEntitySet[baseClass].Add(theEntity); 

      } 
     } 

Il problema che ho è che non esiste una funzione Type.GetAllBaseClassesAndInterfaces - Come andrei a scriverlo?

+0

ma sicuramente non si vuole un esempio di un tipo da contare come come istanza tutti i suoi sotto-tipi e interfacce come bene? –

+0

Apparentemente lo fa. – SLaks

+2

Hai mai pensato che l'uso di Type.IsAssignableFrom (Type) potrebbe rendere la tua vita un po 'più semplice rispetto al tentativo di mappare l'intera gerarchia di ereditarietà di ogni CEntity? Non sei sicuro di cosa esattamente come pensi di usare il repository, ma potrebbe essere qualcosa da guardare. – Rory

risposta

7

tipo ha un BaseType proprietà e un metodo FindInterfaces.

https://msdn.microsoft.com/en-us/library/system.type.aspx

Quindi, in realtà, quasi ha Type.GetAllBaseClassesAndInterfaces, ma è necessario effettuare due chiamate invece di uno.

+0

Vuole ricorrere alla gerarchia dei tipi (quindi GetAllBaseClass ** es **), quindi non è così semplice. – SLaks

+1

Immagino di non essere sicuro se la sua domanda riguardasse quale metodo/proprietà usare, o come scrivere una funzione che attraverserà l'albero dell'ereditarietà. Avevo assunto il primo. –

+0

Potrebbe essere più semplice fare in modo che il costruttore CEntity si registri invece con quel dizionario. Quindi non è necessario interrogare l'albero di ereditarietà per ogni oggetto. L'uso intensivo della riflessione è spesso un'indicazione che qualcosa non va nel tuo progetto. –

14

si potrebbe scrivere un metodo di estensione in questo modo:

public static IEnumerable<Type> GetBaseTypes(this Type type) { 
    if(type.BaseType == null) return type.GetInterfaces(); 

    return Enumerable.Repeat(type.BaseType, 1) 
        .Concat(type.GetInterfaces()) 
        .Concat(type.GetInterfaces().SelectMany<Type, Type>(GetBaseTypes)) 
        .Concat(type.BaseType.GetBaseTypes()); 
} 
+0

dire che ho avuto "Classe Uno: IOne {}" "classe due: uno {}" Come scritto, correre contro typeof (Due) .GetBaseTypes() restituirà multipli di Ione, anche se è implementato solo una volta. Two è un IOne quindi lo restituisce anche se non è implementato esplicitamente. – claudekennilol

+0

@claudekennilol: Quindi aggiungi '.Distinct()'. Vedi anche http://blogs.msdn.com/b/ericlippert/archive/2011/04/04/so-many-interfaces.aspx e http://blogs.msdn.com/b/ericlippert/archive/2011/ 12/08/so-many-interfaces-part-two.aspx – SLaks

+0

OMFG! Questo è un codice seriamente elegante! Molto bella. –

1

di questo codice:

Func<Type, List<Type>> f = ty => 
{ 
    var tysReturn = new List<Type>(); 
    if (ty.BaseType != null) 
    { 
     tysReturn.Add(ty.BaseType); 
    } 
    tysReturn.AddRange(ty.GetInterfaces()); 
    return tysReturn; 
}; 

La funzione f avrà un tipo e restituire un elenco di questo tipo base più interfacce.

Spero che aiuti.

5

risposta più precisa, basata su uno da SLaks sarebbe:

public static IEnumerable<Type> GetBaseClassesAndInterfaces(this Type type) 
{ 
    return type.BaseType == typeof(object) 
     ? type.GetInterfaces() 
     : Enumerable 
      .Repeat(type.BaseType, 1) 
      .Concat(type.GetInterfaces()) 
      .Concat(type.BaseType.GetBaseClassesAndInterfaces()) 
      .Distinct(); 
} 
Problemi correlati