2011-04-26 5 views
1

J'ai plusieurs Enum types définis dans mon projet, utilisés pour les identifiants d'état spécifiques à l'objet:signature générique pour les types Enum

public enum ObjectAState 
    { 
    ObjectAAvailable, 
    ObjectADeleteRequested, 
    ObjectADeleted 
    } 
    public enum ObjectBState 
    { 
    ObjectBCreationRequested, 
    ObjectBCreationFailed, 
    ObjectBDeleteRequested, 
    ObjectBDeleted 
    } 

Toute personne qui utilise ObjectA ne peut se référer à ObjectA énumérations, et la même chose est vraie de tous les autres objets - leurs énumérations sont isolées, ce qui les rend plus faciles à comprendre puisque les états non applicables à un objet ne sont pas affichés (c'est pourquoi je ne mets pas tous les états pour tous les objets dans un seul enum).

Pour un état donné, il y a zéro, un ou plusieurs autres états (au sein du même enum) qui peuvent suivre; par définition, il y a aussi certains états qui ne peuvent pas suivre. Dans ObjectA, par exemple, l'état peut passer de ObjectAAvailable à ObjectADeleteRequested, et de ObjectADeleteRequested à ObjectADeleted, mais pas directement de ObjectAAvailable à ObjectADeleted. Dans chaque objet il y a un peu de code fastidieux et répétitif pour appliquer des transitions d'état valides, que je veux remplacer par une seule méthode.

En tant que test, je l'ai fait:

Dictionary<ObjectAState, List<ObjectAState>> Changes = new Dictionary<ObjectAState, List<ObjectAState>>(); 

C'est un Dictionary accessible via ObjectAState comme une clé, la tenue d'une List d'autres ObjectAState valeurs qui indiquent des transitions valides peuplées ainsi:

Changes.Add(ObjectAState.ObjectAAvailable, new List<ObjectAState> { ObjectAState.ObjectADeleteRequested }); 
Changes.Add(ObjectAState.ObjectAADeleteRequested, new List<ObjectAState> { ObjectAState.ObjectADeleted }); 
Changes.Add(ObjectAState.ObjectADeleted, null); 

Et j'ai une méthode qui ressemble simplement à ceci:

public bool StateTransitionIsValid(ObjectAState currentState, ObjectAState targetState) 
{ 
    return Changes[currentState].Contains(targetState); 
} 

Cela fonctionne parfaitement - les utilisateurs d'ObjectA transmettent simplement dans enum les états actuel et cible de l'objet et obtiennent un simple vrai ou faux pour savoir si la transition est valide. Alors, comment rendre ce générique afin que la même méthode puisse gérer les énumérations d'autres objets?

J'ai essayé ceci:

Dictionary<Enum, List<Enum>> Changes = new Dictionary<Enum, List<Enum>>(); 

Il compile sans erreur - mais le code qui ajoute des entrées au dictionnaire échoue:

Changes.Add(ObjectAState.ObjectAAvailable, new List<ObjectAState> { ObjectAState.ObjectADeleteRequested }); 

Error 1 The best overloaded method match for 'System.Collections.Generic.Dictionary<System.Enum,System.Collections.Generic.List<System.Enum>>.Add(System.Enum, System.Collections.Generic.List<System.Enum>)' has some invalid arguments 
Error 2 Argument 2: cannot convert from 'System.Collections.Generic.List<MyApp.ObjectAState>' to 'System.Collections.Generic.List<System.Enum>' 

J'ai eu une chasse semblent autour et ne peut pour voir ce que je fais mal. Quelqu'un a-t-il des idées pour lesquelles ma version "générique" ne compile pas?

Répondre

1

Je pense qu'il est parce que vous essayez d'utiliser un objet non générique, bien que la définition était générique. essaye ça.

Changes.Add(ObjectAState.ObjectAAvailable, new List<Enum> { ObjectAState.ObjectADeleteRequested }); 
+0

C'est exactement ce dont j'avais besoin - et maintenant je le vois, c'est évident. Doh! –

3

Votre méthode ou classe doit être définie de manière générique afin que vous puissiez utiliser un type générique réel. La difficulté est qu'il n'existe aucun moyen de garantir que le type générique est un Enum au moment de la compilation. Ceci est probablement le plus proche vous venez:

public class MyTestClass<T> 
    where T : struct, IConvertible // Try to get as much of a static check as we can. 
{ 
    // The .NET framework doesn't provide a compile-checked 
    // way to ensure that a type is an enum, so we have to check when the type 
    // is statically invoked. 
    static EnumUtil() 
    { 
     // Throw Exception on static initialization if the given type isn't an enum. 
     if(!typeof (T).IsEnum) 
      throw new Exception(typeof(T).FullName + " is not an enum type."); 
    } 

    Dictionary<T, List<T>> Changes = new Dictionary<T, List<T>>(); 
    ... 
} 
+0

Vous pouvez épingler un peu plus bas: 'où T: struct, IComparable, IConvertible, IFormattable' – LukeH

+0

On dirait que cette réponse est d'essayer de faire en sorte que le type générique est un Enum?Si oui, ce n'était pas vraiment ma question - je n'essayais pas d'appliquer le type Enum, seulement obtenir la définition générique qui fonctionne * avec * un Enum. Merci quand même, cela peut être utile ailleurs. –

Questions connexes