Sé que IList es la interfaz y List es el tipo concreto pero todavía no sé cuándo usar cada uno. Lo que estoy haciendo ahora es que si no necesito los métodos de Ordenar o Buscar Todos, uso la interfaz. ¿Estoy en lo cierto? ¿Hay una mejor manera de decidir cuándo usar la interfaz o el tipo concreto?Cuándo utilizar IList y cuándo utilizar List
Respuesta
Hay dos reglas que siguen:
- aceptar el tipo más básico que trabajará
- Volver los más ricos introduce tu usuario necesitará
Así que cuando se escribe una función o un método que toma una colección, escríbala para no tomar una lista, pero un IList <T>, un ICollection <T> o IEnumerable <T>. Las interfaces genéricas seguirán funcionando incluso para listas heterogéneas porque System.Object también puede ser una T. Hacer esto le ahorrará dolor de cabeza si decide utilizar una pila o alguna otra estructura de datos más adelante en la carretera. Si todo lo que necesita hacer en la función es de por medio, IEnumerable <T> es realmente todo lo que debe pedir.
Por otro lado, al devolver un objeto fuera de una función, desea darle al usuario el conjunto de operaciones más completo posible sin que tenga que dar vueltas. Entonces, en ese caso, si es una lista <T> internamente, devuelva una copia como una lista <T>.
No creo que haya reglas duras y rápidas para este tipo de cosas, pero por lo general sigo las pautas de uso de la manera más liviana posible hasta que sea absolutamente necesario.
Por ejemplo, digamos que usted tiene una clase y una clase Person
Group
. Una instancia de Group
tiene mucha gente, por lo que una Lista aquí tendría sentido. Cuando declaro el objeto de lista en Group
, usaré un IList<Person>
y lo crearé como un List
.
public class Group {
private IList<Person> people;
public Group() {
this.people = new List<Person>();
}
}
Y, si ni siquiera necesita todo en IList
siempre se puede utilizar IEnumerable
también. Con compiladores y procesadores modernos, no creo que haya realmente una diferencia de velocidad, por lo que esto es más una cuestión de estilo.
por qué no convertirlo en un sólo una lista en el primer lugar? Todavía no entiendo por qué la bonificación que obtienes por convertirla en IList luego en el constructor lo haces en una lista <> – chobo2
Estoy de acuerdo, si estás creando explícitamente un objeto List
En situaciones que generalmente encuentro, rara vez uso IList directamente.
Por lo general sólo lo utilizan como un argumento a un método
void ProcessArrayData(IList almostAnyTypeOfArray)
{
// Do some stuff with the IList array
}
Esto permitirá que haga el procesamiento genérico en casi cualquier matriz en el marco .NET, a menos que se utiliza IEnumerable y no IList, lo que ocurre a veces.
Realmente se reduce al tipo de funcionalidad que necesita. Sugeriría usar la clase List en la mayoría de los casos. IList es mejor para cuando necesita crear una matriz personalizada que podría tener algunas reglas muy específicas que le gustaría encapsular dentro de una colección para que no se repita, pero aún desea que .NET la reconozca como una lista.
Si trabaja con un único método (o incluso en una única clase o ensamblaje en algunos casos) y nadie va a ver lo que está haciendo, utilice la plenitud de una lista. Pero si está interactuando con un código externo, como cuando devuelve una lista de un método, solo quiere declarar la interfaz sin vincularse necesariamente con una implementación específica, especialmente si no tiene control sobre quién compila en su contra. codificar después Si comenzó con un tipo concreto y decidió cambiar a otro, incluso si utiliza la misma interfaz, va a romper el código de otra persona a menos que haya comenzado con una interfaz o tipo de base abstracta.
Debe usar la interfaz solo si la necesita, por ejemplo, si su lista se convierte en una implementación IList que no sea List. Esto es cierto cuando, por ejemplo, utiliza NHibernate, que arroja ILists en un objeto de bolsa NHibernate cuando recupera datos.
If List es la única implementación que alguna vez usará para una cierta colección, no dude en declararla como una implementación concreta de List.
Siempre es mejor usar el tipo de base más bajo posible. Esto le da al implementador de su interfaz, o consumidor de su método, la oportunidad de usar lo que quiera detrás de escena.
Para las colecciones, debe apuntar a utilizar IEnumerable siempre que sea posible. Esto le da la mayor flexibilidad, pero no siempre es adecuado.
Siempre es mejor ** aceptar ** el tipo base más bajo posible. Regresar es una historia diferente. Elija qué opciones pueden ser útiles. Entonces, ¿cree que su cliente podría querer usar el acceso indexado? Evitar que 'ToList()' '-ing su devuelto IEnumerable
Estoy de acuerdo con los consejos de Lee para tomar los parámetros, pero no regresar.
Si especifica sus métodos para devolver una interfaz, significa que es libre de cambiar la implementación exacta más adelante sin que el método de consumo lo sepa. Pensé que nunca necesitaría cambiar de una lista < T> pero tuve que cambiar más tarde para usar una biblioteca de listas personalizada para la funcionalidad adicional que proporcionaba. Como solo había devuelto IList < T> ninguna de las personas que usaban la biblioteca tuvo que cambiar su código.
Por supuesto, solo es necesario aplicarlo a métodos que son visibles externamente (es decir, métodos públicos). Yo personalmente uso interfaces incluso en código interno, pero como usted mismo puede cambiar todo el código si realiza cambios de última hora, no es estrictamente necesario.
directrices de Microsoft como controladas por FxCop desalentar el uso de la Lista <T> en API públicas - prefieren IList <T>.
Por cierto, ahora casi siempre declarar matrices unidimensionales como IList <T>, que significa que puedo utilizar consistentemente la propiedad .Count IList <T> en lugar de Array.length. Por ejemplo:
public interface IMyApi
{
IList<int> GetReadOnlyValues();
}
public class MyApiImplementation : IMyApi
{
public IList<int> GetReadOnlyValues()
{
List<int> myList = new List<int>();
... populate list
return myList.AsReadOnly();
}
}
public class MyMockApiImplementationForUnitTests : IMyApi
{
public IList<int> GetReadOnlyValues()
{
IList<int> testValues = new int[] { 1, 2, 3 };
return testValues;
}
}
¡Me gusta más esta explicación/ejemplo! – JonH
Relacionados: http://stackoverflow.com/questions/5968708/why-array-implements-ilist – Panzercrisis
usted muy a menudo mejor de utilizar el tipo que se usan más general, en este caso el IList o incluso mejor la interfaz IEnumerable, por lo que se puede cambiar la implementación convenientemente en un momento posterior.
Sin embargo, en .NET 2.0, hay algo molesto: IList no tiene un método Sort(). Puede utilizar un adaptador suministrado en su lugar:
ArrayList.Adapter(list).Sort()
IEnumerable usted debe tratar de utilizar el tipo menos específico que se adapte a su propósito.IEnumerable es menos específico que IList Se utiliza IEnumerable cuando se quiere recorrer los elementos de una colección
IList IList implementa IEnumerable Debe utilizar IList cuando se necesita el acceso de índice para su colección, agregar y eliminar elementos, etc ..
lista lista implementa IList
Respuesta excelente y clara, que marqué como útil. Sin embargo, agregaría que para la mayoría de los desarrolladores, la mayoría de las veces, no vale la pena preocuparse por la pequeña diferencia en el tamaño y el rendimiento del programa: si tiene dudas, solo use una Lista. –
objeto AList le permite crear una lista, añadir cosas a ella, quita, actualizarlo, índice en ella y etc. lista se usado siempre que solo desee una Lista genérica donde especifique el tipo de objeto y eso es todo.
IList por el contrario es una interfaz. Básicamente, si usted desea crear su propio tipo de lista, diga una clase llamada BookList lista, entonces usted puede utilizar la interfaz para darle métodos básicos y estructura a su nueva clase. IList es para cuando quieres crear tu propia subclase especial que implemente Lista.
Otra diferencia es: IList es una interfaz y no se puede crear una instancia. La lista es una clase y se puede crear una instancia. Significa:
IList<string> MyList = new IList<string>();
List<string> MyList = new List<string>
Hay una cosa importante que la gente siempre parecen pasar por alto:
puede pasar un array plano a algo que acepta un parámetro IList<T>
, y entonces usted puede llamar IList.Add()
y recibirán un tiempo de ejecución excepción:
Unhandled Exception: System.NotSupportedException: Collection was of a fixed size.
Por ejemplo, considere el siguiente código:
private void test(IList<int> list)
{
list.Add(1);
}
Si se llama a que la siguiente manera, obtendrá una excepción de tiempo de ejecución:
int[] array = new int[0];
test(array);
Esto sucede porque el uso de matrices de civil con IList<T>
viola el principio de sustitución Liskov.
Por esta razón, si está llamando al IList<T>.Add()
, puede considerar requerir un List<T>
en lugar de un IList<T>
.
Esto es trivialmente cierto para todas las interfaces. Si desea seguir con su argumento , entonces podría argumentar que nunca use ninguna interfaz, porque podría arrojar alguna implementación. Si, por otro lado, considera la sugerencia dada por OP para preferir 'List
@MichaWiedenmann Mi respuesta aquí es específica a cuando llamas 'IList
- 1. Cuándo utilizar un HashTable
- 2. Cuándo utilizar retener y cuándo utilizar la copia
- 3. Cuándo utilizar/proc y cuándo/dev
- 4. Cuándo utilizar Request.UrlReferrer y cuándo Request.ServerVariables ["HTTP_REFERER"]?
- 5. cuándo utilizar "willChangeValueForKey" y "didChangeValueForKey"?
- 6. Cuándo utilizar Runtime.maxMemory() y totalMemory()
- 7. Cuándo utilizar la opción
- 8. Cuándo utilizar NSNotificationCenter
- 9. Cuándo utilizar archivos .xcconfig
- 10. Cuándo utilizar WCF/REST
- 11. cuándo utilizar hibernate.connection.provider_class
- 12. Cuándo utilizar importaciones absolutas
- 13. Cuándo utilizar NSEnumerationConcurrent
- 14. Cuándo utilizar Dependency Injection
- 15. ¿Cuándo NO utilizar NoSQL?
- 16. Cuándo utilizar el operador "^"
- 17. Cuándo utilizar memcached
- 18. Cuándo utilizar ServiceTracker vs ServiceReference
- 19. Cuándo utilizar Value Formatter y cuándo usar Value Resolver
- 20. Cuándo utilizar los punteros, y cuándo no usarlos
- 21. Cuándo utilizar una clave principal autoincrementada y cuándo no?
- 22. Cuándo utilizar 'if ... else if' y cuándo usar
- 23. Cuándo utilizar TemplateBinding y TemplatedParent en WPF
- 24. Comprender cuándo y cómo utilizar Require.JS
- 25. Cuándo utilizar VARCHAR y FECHA/DATETIME
- 26. cuándo utilizar OPTIMIZE en mysql
- 27. - Cuándo utilizar DataContractSerializer/Binario/XMLSerialiser
- 28. Cuándo utilizar IModelBinder versus DefaultModelBinder
- 29. Cuándo utilizar punteros en C++
- 30. Cuándo utilizar pathParams o QueryParams
No debe tratar los tipos de entrada/salida de manera diferente. Los tipos de entrada y salida deben * ambos * ser el tipo más básico (preferiblemente la interfaz) que respaldará las necesidades de los clientes. La encapsulación se basa en decirle a los clientes tan poco sobre la implementación de su clase como sea posible. Si devuelve una Lista concreta, no podrá cambiar a otro tipo mejor sin forzar a todos sus clientes a volver a compilar/actualizar. – Ash
No estoy de acuerdo con las 2 reglas ...Usaría el tipo más primitivo y especialmente cuando regrese en este caso IList (mejor IEnumarable) y deberías trabajar con List en tu función dentro. Luego, cuando necesite "agregar" u "ordenar", utilice la Colección si necesita más y luego use Lista. Así que mi regla sería: COMIENCE siempre con IENumarable y si necesita más, extienda ... – ethem
Para su comodidad, las "dos reglas" tienen un nombre: [principio de solidez (también conocido como Ley de Postel)] (https: // es .wikipedia.org/wiki/Robustness_principle). – easoncxz