2009-08-26 7 views
10

Tengo una situación en la que tengo un objeto comercial con aproximadamente 15 propiedades de diferentes tipos. El objeto de negocio también tiene que implementar una interfaz que tiene el siguiente método:.NET: switch vs dictionary para claves de cadena

object GetFieldValue(string FieldName); 

puedo ver 2 maneras de implementar este método:

Uso de una sentencia switch:

switch (FieldName) 
{ 
    case "Field1": return this.Field1; 
    case "Field2": return this.Field2; 
    // etc. 
} 

Utilice un diccionario (SortedDictionary o HashTable?):

return this.AllFields[FieldName]; 

que sería más eficiente?

Agregado: Olvidó decir. Este método es para mostrar el artículo en una grilla. La grilla tendrá una columna para cada una de estas propiedades. Habitualmente habrá cuadrículas con un poco más de 1000 elementos en ellas. Por eso me preocupa el rendimiento.

Agregado 2:

He aquí una idea: un enfoque híbrido. Cree un diccionario estático con claves que sean nombres de propiedad y valores que sean índices en matriz. El diccionario se completa solo una vez, al inicio de la aplicación. Cada instancia de objeto tiene una matriz. Por lo tanto, la búsqueda sería como la siguiente:

return this.ValueArray[StaticDictionary[FieldName]]; 

El algoritmo de relleno del diccionario puede usar la reflexión. Las propiedades en sí entonces se ejecutarán en consecuencia:

public bool Field1 
{ 
    get 
    { 
     object o = this.ValueArray[StaticDictionary["Field1"]]; 
     return o == null ? false : (bool)o; 
    } 
    set 
    { 
     this.ValueArray[StaticDictionary["Field1"]] = value; 
    } 
} 

Puede alguien ver ningún problema con esto?

También se puede tomar un paso más y ValueArray/StaticDictionary se puede colocar en un tipo genérico separado ValueCollection<T>, donde T especificaría el tipo de reflejo. ValueCollection también manejará el caso cuando aún no se haya establecido ningún valor. Propiedades podrían entonces ser escritas simplemente como:

public bool Field1 
{ 
    get 
    { 
     return (bool)this.Values["Field1"]; 
    } 
    set 
    { 
     this.Values["Field1"] = value; 
    } 
} 

Y al final, estoy empezando a preguntarse de nuevo, si una declaración simple cambio podría no ser más rápido y más fácil de mantener ....

+0

¿Hay algún motivo por el que no vincule todo el objeto a la cuadrícula como un datarow? –

+0

A decir verdad, es la cosa de DevExpress TreeList. Es como un híbrido treeview/gridview. Entonces los datos tienen que ser jerárquicos. Y la interfaz está ahí para que TreeList comprenda la jerarquía 'n cosas. Probablemente también podría traducirlo todo a una DataTable (también puede vincularse a eso), pero luego me resultará más cómodo trabajar con ella. –

+0

Quiero decir, también haré otras cosas con esta estructura de datos, no solo la mostraré en la grilla. –

Respuesta

21
switch:  good efficiency, least maintainable 
dictionary: good efficiency, better maintainability 
reflection: least efficient, best maintainability 

Sugerencia: ignore la eficiencia y preocúpese únicamente por el mantenimiento, a menos que en realidad haya probado el rendimiento y haya encontrado un problema.

No estoy diciendo que la reflexión sea su única opción, solo que le permite agregar/eliminar y cambiar el nombre de las propiedades según sea necesario, y no es necesario mantener sincronizada la instrucción de cambio o el diccionario.

+0

Hmm ... bueno ... vale ... –

+0

La reflexión permitiría descubrir tus propiedades en tiempo de ejecución y, por lo tanto, si agregas/elimine o cambie el nombre de cualquiera, no necesita volver a escribir ningún otro código (como la instrucción de conmutación o la inicialización del diccionario). – Ash

+7

Tiendo a encontrar que la sobrecarga cognitiva de la reflexión lo hace algo menos fácil de mantener que el enfoque del diccionario de la tabla de despacho. Aunque puede ser porque no uso el reflejo muy a menudo. :) –

7

Como está utilizando cadenas de caracteres, el diccionario probablemente sea más rápido. Switch esencialmente se traducirá a una tabla hash al usar cadenas. Pero si está utilizando Ints o similar, se traduce a una tabla de salto y será más rápido.

ver this answer y pregunta para más detalles

La mejor opción es el perfil it y encontrar a ciencia cierta

0

¿Cómo se obtiene el valor de cada propiedad, probablemente tendrá un menor impacto en el rendimiento global de cómo se renderiza tu cuadrícula

Déjeme darle un ejemplo: digamos que tiene la siguiente implementación:

private string _latestFieldName = string.Empty; 
private PropertyInfo _propertyInfo; 

object GetFieldValue(string FieldName) 
{ 
    if(FieldName != _latestFieldName) 
    { 
    _propertyInfo = typeof(yourTypeName).GetProperty(FieldName); 
    } 
    return _propertyInfo.GetValue(this,null); 
} 

Si su prestación rejilla está prestando una fila a la vez utilizando la reflexión que tendrá que obtener la PropertyInfo cada vez . mientras que si renderiza columna por columna, solo tendría que obtener PropertyInfo una vez para cada propiedad y dado que la predicción de rama será correcta casi siempre perderá unos pocos ciclos de reloj en el if. Cuando ya tiene PropertyInfo y no necesita enviar el resultado de la llamada a GetValue. usar reflection viene MUY cerca de usar el captador de una propiedad cuando se trata de velocidad.

Mi punto es antes de comenzar a optimizar el uso de un generador de perfiles. (Por supuesto, si no se puede cambiar así la red realmente no se puede optimizarlo tampoco)

+0

Nop, no puedo cambiar la cuadrícula. :) –

0

interruptor en realidad tiene 2 beneficios en comparación con el diccionario:

  1. puede crear mensaje de excepción personalizada en la sección predeterminada que puede incluir un valor no válido En el caso del diccionario, solo obtiene KeyNotFoundException que no contenía el nombre de la clave.
  2. Puede manejar valores nulos. El diccionario no puede almacenar nulo como una clave.