2010-03-05 5 views
5

J'ai un scénario dans lequel j'utilise un dictionnaire pour contenir une liste de types de transactions qu'un certain système accepte. La clé dans le dictionnaire est un champ enum, la valeur est un int.Problème avec une énumération en tant que clé dans une collection de dictionnaire

À un certain moment dans le système, nous allons vouloir faire quelque chose comme ceci:

sqlCommand.Parameters.AddWithValue("@param", LookupDictionary[argument.enumField]); 

Quand nous regardons le champ dans le dictionnaire, nous allons obtenir la valeur entière correcte pour alimenter la base de données. J'ai pensé à utiliser la valeur enum int pour cela, mais ce n'est pas tout à fait correct. Nous interagissons avec un système dans lequel nous devons fournir un nombre magique pour représenter le type de mise à jour que nous faisons.

Le code ci-dessus fonctionne très bien. J'ai une méthode d'initialisation qui ajoute les types connus:

LookupDictionary = new Dictionary<mynamespace.myproject.myclass.enumType, int>(); 
LookupDictionary.Add(enumType.entry1, 4); 
LookupDictionary.Add(enumType.entry2, 5); 
LookupDictionary.Add(enumType.entry3, 6); 

Ce code fonctionne également très bien. Mais au-dessus, avant que j'utilise réellement le LookupDictionary, je valide que la requête faite est réellement définie à une valeur d'énumération que nous soutenons. C'est la raison principale de LookupDictionary, il contient les entrées valides (il y a des entrées enum valides avec lesquelles cette méthode ne fonctionne pas).

Ceci est le code qui ne fonctionne pas: le système ne reconnaît pas que les énumérations correspondent. Dans le débogueur, je peux voir que la liste des entrées dans LookupDictionary montre qu'il a la valeur pour entry2 - il l'appelle comme ça, entry2. L'enumField entrant d'un autre côté a l'espace de noms complet; mynamespace.myproject.myclass.enumType.entry2 - J'imagine que c'est pourquoi il ne les voit pas comme étant les mêmes. Ai-je mentionné que cela est passé à travers un service WCF? Mais je n'utilise pas un proxy généré automatiquement ... les deux projets des deux côtés du fil partagent les types comme référence de projet, et je crée mon client de canal dans le code.

Des idées? Est-ce que je le fais mal? Est-ce que les dictionnaires avec Enums comme clés ne fonctionnent pas bien? Est-ce une chose WCF?

Note: merci pour les suggestions concernant le réglage des enums pour contenir le magic int. Je voulais toutefois les mettre dans une configuration, car il est possible que les «numéros magiques» 4 5 et 6 changent à l'avenir. Donc, si je les code dans l'ENUM comme suggéré:

public enum MyEnum 
{ 
    MyValue1 = 4, 
    MyValue2 = 5, 
    MyValue3 = 6 
} 

je perds la possibilité d'écrire une méthode qui met en place au moment de l'exécution des numéros magiques dans l'avenir; Au lieu de cela, il faudrait un changement de code.

+3

Un dictionnaire n'a aucun problème avec les types d'énumération en tant que clés, et je doute qu'il soit lié à WCF. Il n'y a ici que de minuscules extraits de code - un programme court mais complet qui reproduit le problème pourrait probablement apporter quelques réponses. Commencez par le cas le plus simple possible - ajoutez une clé d'énumération à un dictionnaire et vérifiez qu'elle est présente. Ensuite, construisez progressivement jusqu'à ce que vous frappiez sur l'endroit où votre code échoue. – Aaronaught

+0

Je suis sûr que vous avez raison. J'ai le sentiment fort que j'ai juste une petite erreur quelque part; Je pensais juste que je le jetterais là-bas. Au moins un membre de la WCF que je connais a pensé qu'il pourrait s'agir des proxies générés automatiquement, c'est pourquoi je me suis réorganisé sur la base d'un projet partagé pour mes DataContracts. Tout s'est bien passé, mais cela n'a pas réglé le problème. –

Répondre

3

Au lieu d'utiliser la ENUM comme la clé, utilisez la représentation entière de l'ENUM.

Par exemple:

LookupDictionary = new Dictionary<int, int>(); 
LookupDictionary.Add((int)enumType.entry1, 4); 
LookupDictionary.Add((int)enumType.entry2, 5); 
LookupDictionary.Add((int)enumType.entry3, 6); 

De cette façon, vous pouvez utiliser la même méthode 'ContainsKey' du dictionnaire. Je ne suis pas sûr que ce soit une meilleure performance qu'un List<int>

+0

hmm, merci ... J'aime ça ... je vais essayer. Cela devrait me donner la même maintenabilité que je voulais, et garder la possibilité de la réécrire à partir d'une config plus tard. –

+0

A travaillé! Je ne sais toujours pas ce qui se passe ... il y a d'autres champs qui sont transmis à ce service qui ne «passent pas» correctement, donc je soupçonne un problème ailleurs; mais cela résout mon problème. Merci! –

0

Pouvez-vous envisager de taper explicitement votre énumération comme int (ou quel que soit le type sous-jacent), puis de définir la valeur de chacune de vos énumérations sur la valeur de la base de données? Vous avez déjà étroitement couplé l'énumération à la base de données, donc la relation sera dictée en C# (codage en cours) ou par SQL (peut-être un proc qui retourne l'ID ainsi qu'une chaîne qui peut être analysée dans une énumération .)

en supposant que votre énumération est un int ...

enum enumType { 
    entry1 = 4, 
    entry2 = 5, 
    entry3 = 6 
} 

Lorsque vous ajoutez votre paramètre alors vous simplement jeté comme type sous-jacent de l'ENUM.

sqlCommand.Parameters.AddWithValue("@param", (int)argument.enumField); 
+0

L'énumération existe pour représenter des valeurs valides dans la base de données, être étroitement couplé n'est pas un problème. Le problème est que je voudrais être capable de générer les «nombres magiques» corrects au moment de l'exécution au cas où ils changeraient. Si je les mets comme vous l'indiquez, entry1 = 4, je ne peux pas envelopper une boucle autour de lui. Les valeurs réelles ne changeront pas, juste leurs représentations int. Par exemple, entry1 pourrait être 4 aujourd'hui mais il pourrait être 40 dans une semaine. Le Lookup.Add me permet d'écrire une méthode plus tard qui irait et tirer les bonnes valeurs magiques de la base de données et les stocker dans le dictionnaire de recherche. –

1

Vous ne devriez pas avoir besoin d'une table de recherche tout ici:

public enum MyEnum 
{ 
    MyValue1 = 4, 
    MyValue2 = 5, 
    MyValue3 = 6 
} 

// Sample usage 
MyEnum firstEnum = MyEnum.MyValue1; 
int intVal = (int)firstEnum; // results in 4 

// Enum Validation 
bool valid = Enum.IsDefined(typeof(MyEnum), intVal); // results in true 
+0

L'énumération a des entrées que cette méthode ne peut pas gérer. Le but de la recherche est donc de vérifier si nous sommes appelés avec une requête définie sur l'un de ces types que nous ne pouvons pas gérer. –

0

Vous pouvez définir explicitement les valeurs de l'ENUM en utilisant la syntaxe

enum ArgumentTypes { 
    Arg1 = 1; 
    Arg2 = 3; 
    Arg3 = 5; 
} 

Vous n'avez pas besoin pour garder chaque valeur séquentielle dans l'énumération pour que cette syntaxe fonctionne.

Pour valider que seuls les paramètres valides pour la méthode sont utilisés, essayez cet exemple de code. Remarque: Je suggère d'utiliser une exception ArgumentException sur une exception InvalidOperationException dans ce contexte.

public void DoDbWork(ArgumentTypes argType, object otherParameter) 
{ 
    if (argType == ArgumentTypes.Arg3) { 
     throw new ArgumentException("Argument of value " + argType + " is not valid in this context", "argType"); 
    } 

    // Handle db transaction here 
} 

Pour ajouter la valeur int comme paramètre:

cmd.Parameters.AddWithValue("@paramName", (int)argType); 
Questions connexes