2010-12-16 15 views
5

¿Es una buena práctica declarar variables utilizando la interfaz? En mi compañía tuvimos una discusión sobre eso y estoy en contra de eso.¿Es una buena/aceptable práctica declarar variable como tipo de interfaz?

p. Ej. Quería tener una colección que almacenara claves de cadena y pares de valores de cadena. No quiero permitir duplicados tampoco. Así que claramente declare la variable Diccionario en mi clase que sería expuesta públicamente (a través de la propiedad).

Dictionary<string, string> myDic; 

Sin embargo, un miembro del equipo dice que ¡no es una buena práctica! Él está diciendo que declaras una variable con IDictionary y esto permitirá a los consumidores asignar cualquier colección (implementando IDictionary) que deseen. p.ej. Tabla hash o Diccionario

IDictionary myDic; 
myDic = new Hashtable(); // Consumer's code 

O

mydic = new Dictionary<string, string>(); // Consumer's code -

¿Se puede saber ahora, ¿es realmente una buena práctica para declarar variables como el tipo de interfaz? ¿Y eso también cuando sé claramente qué se espera de esa variable?

+0

¿Y si algún día pronto Microsoft reemplaza Dictionary <> con SuperDuperDictionary <>, y una persona utiliza su clase no podrá para aprovecharlo? –

Respuesta

12

Para variables locales, campos privados, etc., solo está dividiendo pelos. Hay un beneficio para definir propiedades públicas usando un tipo de interfaz. Por ejemplo, me estremezco cuando veo una clase que expone una propiedad del tipo List<string>.

Si está utilizando inyección de dependencias o un marco de composición como MEF, se recomienda encarecidamente utilizar interfaces en lugar de implementaciones concretas. Le permite intercambiar implementaciones fácilmente con implementaciones de prueba.

+2

+1, porque para locales/privados está dividiendo cabellos. Además, defiendo el uso de 'var' donde no perjudica la legibilidad/comprensibilidad, ya que reduce aún más el impacto de los cambios de código :) –

1

Diccionario myDic;

es una variable de nivel de clase privada, por lo que ningún consumidor puede modificarla.

segundo si su son realmente preocupados por IDictionary de lo que puede crear una clase genérica #

Public Class MiClase < T> donde T: Diccionario < T Key, T Fuente>

y de definir el varaible de MyClass

1

yo personalmente prefiero algo más parecido a esto:

var statesByPostalCode = states.ToDictionary(s => s.PostalCode); 

Mediante el uso de var, el compilador/IDE puede todavía le diga qué es, qué métodos están disponibles, etc. El tipo puede cambiar de un diccionario a IDictionary con un mínimo esfuerzo:

var statesByPostalCode = GetStatesByPostalCode(); 
var myState = statesByPostalCode[myStateCode]; 

en las declaraciones anteriores, la GetStatesByPostalCode método() podría devolver un diccionario o IDictionary, o alguna otra colección que proporciona un controlador paso a paso basado en cadena, y su tipo de retorno podría cambiar de alguna otra fi en alguna parte, y no tendrías que cambiar esta línea de código. Mientras tanto, el nombre, statesByPostalCode indica qué tiene realmente esta variable: una colección donde puede buscar cada estado por su código postal.

+0

No funciona para las variables miembro: ¿Interfaces o tipos concretos? –

+0

Tienes razón. Cuando leí la pregunta la primera vez, pensé que estábamos hablando de variables locales. Para las propiedades expuestas públicamente, etc., usaría una interfaz genérica. – StriplingWarrior

1

La interfaz es mejor, pero la selección de la interfaz correcta es el problema principal en su ejemplo. ¿No puedes usar IDictionary<string, string> en su lugar?

5

En su interfaz pública, generalmente debe tratar de exponer un tipo abstracto que satisfaga los requisitos de su usuario (incluso si su "usuario" es su propio código).

Debe asignar buenos valores predeterminados para estos tipos genéricos, para que pueda comenzar a utilizarlos lo antes posible en su código, en lugar de tener que crear y asignar un tipo concreto cada vez que quiera usarlo.

Un ejemplo:

public class Something 
{ 
    public Something() 
    { 
    this.Map = new Dictionary<string, string>(); 
    } 

    public IDictionary<string, string> Map { get; set; } 
} 

Esto permite que el usuario de la clase, o el implementador, para cambiar a un nuevo tipo de diccionario sin romper el código existente, pero al mismo tiempo no requiere que el usuario escriba este código cada vez que lo utilizan:

var something = new Something(); 
something.Map = new Dictionary<string, string>(); 

se puede simplemente comenzar a usarlo:

var something = new Something(); 
something.Map["test"] = "some value"; 

Ejemplos de otros tipos:

public IEnumerable<string> ValuesReadOnly { get; private set; } // Read-only access 
public IEnumerable<string> ValuesReadWrite { get; set; } // Sequence read-write access 
public IList<string> ValuesRandomReadWrite { get; set; } // Random read-write access 

Una buena razón para hacer esto es por lo que se puede conectar en cualquier tipo en el futuro, sin tener que convertirlo en el tipo específico que ha definido. Nada contamina el código más rápido que tener que hacer conversiones ay desde varios tipos.

Por ejemplo, encuentro que uso IEnumerable mucho cuando uso Linq. Si tuviera List<T> para mis miembros públicos, siempre tendría que convertir los valores en listas antes de asignarlos, lo que no solo aumenta mi código, sino que también perjudica el rendimiento. Tienes que hacer otra copia de la estructura de la lista en la memoria, y no puedes aprovechar cosas como las secuencias de evaluación diferida/yield return.

Un ejemplo de esto:

public class Something2 
{ 
    public IEnumerable<string> SomeValues { get; set; } 
} 

var dbQuery = BuildQuery("select item from inventory where item.Price > 5.00"); 
var something = new Something(); 
something.SomeValues = dbQuery.Evaluate(); // Imagine if this did paging... 

En lugar de:

public class Something2 
{ 
    public List<string> SomeValues { get; set; } 
} 

var dbQuery = BuildQuery("select item from inventory where item.Price > 5.00"); 
var something = new Something(); 
something.SomeValues = dbQuery.Evaluate().ToList(); // Has to evaluate all of them... 
Cuestiones relacionadas