2010-03-05 5 views
5

Tengo un escenario en el que estoy usando un diccionario para contener una lista de tipos de transacciones que acepta un determinado sistema. La clave en el Diccionario es un campo enum, el valor es un int.Problema con una enumeración como clave en una colección de diccionarios

En algún punto del sistema, vamos a querer hacer algo como esto:

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

Cuando miramos el campo en el diccionario, vamos a obtener el valor entero correcta para alimentar a la base de datos. He pensado en usar realmente el valor enum int para esto, pero eso no es exactamente correcto. Estamos interactuando con un sistema donde necesitamos alimentar un número mágico para representar el tipo de actualización que estamos haciendo.

El código anterior funciona bien. Tengo un método de inicialización que añade los tipos conocidos:

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

Este código también funciona bien.

Pero arriba, antes de entrar al uso de LookupDictionary, confirmo que la solicitud que se está realizando está realmente configurada en un valor enum que admitimos. Esa es la razón principal de LookupDictionary, contiene los válidos (hay entradas enum válidas con las que este método no funciona).

Este es el código que no funciona: el sistema no reconoce que las enumeraciones coinciden. En el depurador, puedo ver que la lista de entradas en LookupDictionary muestra que tiene el valor para entry2; simplemente lo llama así, entry2. El enumField entrante, por otro lado, tiene el espacio de nombre completo; mynamespace.myproject.myclass.enumType.entry2 - Me imagino que es por eso que no los ve como iguales.

if (!LookupDictionary.ContainsKey(argument.enumField)) 
{ 
    throw new InvalidOperationException("argument.enumField not valid in blahMethod."); 
} 

¿He mencionado que esto se está transmitiendo a través de un servicio de WCF? Pero no estoy usando un proxy autogenerado ... ambos proyectos en ambos lados del cable comparten los tipos como referencia de proyecto, y construyo mi cliente de canal en código.

¿Alguna idea? ¿Lo estoy haciendo mal? ¿Los diccionarios con enumeraciones como claves no funcionan bien? ¿Es una cosa de WCF?

Nota: gracias por las sugerencias con respecto a la configuración de las enumeraciones para contener la magia int. Sin embargo, quería establecerlos en una configuración, ya que es posible que los "números mágicos" 4 5 y 6 cambien en el futuro. Así que si yo codificarlos en la enumeración como se sugiere:

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

que pierden la capacidad de escribir un método que pone en marcha los números mágicos en el futuro en tiempo de ejecución; en cambio, requeriría un cambio de código.

+3

Un diccionario no tiene ningún problema con los tipos de enumeración como claves, y dudo que esté relacionado con WCF. Aquí solo hay pequeños fragmentos de código: un programa breve pero completo que reproduzca el problema probablemente genere algunas respuestas. Comience con el caso más simple posible: agregue una clave de enumeración a un diccionario y verifique que esté allí. Luego, protéjala gradualmente hasta que toques el lugar donde falla tu código. – Aaronaught

+0

Estoy seguro de que tienes razón. Tengo una fuerte sensación de que acabo de tener algún pequeño error en alguna parte; solo pensé en tirarlo allí. Al menos una persona de WCF que conozco pensó que podrían ser los proxies autogenerados, por lo que me reorganicé en base a un proyecto compartido para mis DataContracts. Todo fue genial, pero no solucionó el problema. –

Respuesta

3

En lugar de utilizar la enumeración como la clave, utilizar la representación entera de la enumeración.

Por ejemplo:

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

De esta manera, se puede utilizar el mismo método 'ContainsKey' del diccionario. No estoy seguro de que este sea un rendimiento mucho mejor que List<int>

+0

hmm, gracias ... Me gusta esto ... voy a intentarlo. Debería darme la misma facilidad de mantenimiento que quería, y mantener la capacidad de volver a escribirlo desde una configuración posterior. –

+0

¡Funcionó! Todavía no estoy seguro de lo que está pasando ... hay otros campos que se transfieren a este servicio que no se "transmiten" correctamente, por lo que sospecho que hay un problema en otro lado; pero esto solucionó mi problema. ¡Gracias! –

0

¿Ha considerado escribir su enumeración explícitamente como int (o cualquiera que sea el tipo subyacente) y luego establecer el valor de cada una de sus enumeraciones en el valor de la base de datos? Ya ha acoplado estrechamente la enumeración a la base de datos, por lo que la relación se dictará en C# (codificación actual) o SQL (tal vez un proceso que devuelva la ID así como una cadena que se pueda analizar en una enumeración) .)

Utilizando el supuesto de que su enumeración es un int ...

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

al agregar el parámetro que haría a continuación, sólo echado como tipo subyacente de la enumeración.

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

La enumeración existe para representar valores válidos en la base de datos, ya que estar estrechamente unido no es un problema. El problema es que me gustaría poder generar los "números mágicos" correctos en tiempo de ejecución en caso de que cambien. Si los configuro como indica, entry1 = 4, no puedo envolverlos. Los valores reales no cambiarán, solo sus representaciones int podrían. Por ejemplo, entry1 podría ser 4 hoy, pero podría ser 40 en una semana. El Lookup.Add me permite escribir un método más tarde que iría y extraería los valores mágicos correctos del DB y los almacenaría en el diccionario de búsqueda. –

1

Usted no debe necesitar una tabla de búsqueda aquí en absoluto:

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

La enumeración tiene entradas que este método no puede manejar. Entonces, el objetivo de la búsqueda es verificar si se nos llama con un conjunto de solicitudes a uno de esos tipos que no podemos manejar. –

0

Usted puede establecer explícitamente los valores de la enumeración utilizando la sintaxis

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

No es necesario para mantener cada valor secuencial en la enumeración para que funcione esta sintaxis.

Para validar que solo se usan parámetros que son válidos para el método, intente con este código de muestra. Nota: sugiero usar una ArgumentException sobre una InvalidOperationException en este contexto.

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 
} 

Para añadir el valor int como el parámetro:

cmd.Parameters.AddWithValue("@paramName", (int)argType); 
Cuestiones relacionadas