volver trailer sobre rotos reparto pelicula mala madre los kika film español educacion completa cancion abrazos c# .net interface abstraction

c# - trailer - ¿Devolver IList<T> es peor que devolver T[] o List<T>?



volver cancion (5)

Al igual que con todas las preguntas de "interfaz versus implementación", tendrá que darse cuenta de lo que significa exponer a un miembro público: define la API pública de esta clase.

Si expone una List<T> como miembro (campo, propiedad, método, ...), le dice al consumidor de ese miembro: el tipo obtenido al acceder a este método es una List<T> , o algo derivado de eso .

Ahora, si expone una interfaz, oculta el "detalle de implementación" de su clase utilizando un tipo concreto. Por supuesto, no puede crear una instancia de IList<T> , pero puede usar una Collection<T> , List<T> , derivaciones de la misma o su propio tipo que implementa IList<T> .

La pregunta real es "¿Por qué Array implementa IList<T> " o "¿Por qué la interfaz IList<T> tantos miembros?"

También depende de lo que quiera que hagan los consumidores de ese miembro. Si realmente devuelve un miembro interno a través de su miembro Expose... , querrá devolver una new List<T>(internalMember) todos modos, de lo contrario, el consumidor puede intentar enviarlos a IList<T> y modificar su interno miembro a través de eso.

Si solo espera que los consumidores repitan los resultados, exponga IEnumerable<T> o IReadOnlyCollection<T> lugar.

Las respuestas a preguntas como esta: Lista <T> o IList <T> siempre parecen estar de acuerdo en que devolver una interfaz es mejor que devolver una implementación concreta de una colección. Pero estoy luchando con esto. Es imposible crear instancias de una interfaz, por lo que si su método devuelve una interfaz, en realidad sigue devolviendo una implementación específica. Estaba experimentando un poco con esto escribiendo 2 pequeños métodos:

public static IList<int> ExposeArrayIList() { return new[] { 1, 2, 3 }; } public static IList<int> ExposeListIList() { return new List<int> { 1, 2, 3 }; }

Y usarlos en mi programa de prueba:

static void Main(string[] args) { IList<int> arrayIList = ExposeArrayIList(); IList<int> listIList = ExposeListIList(); //Will give a runtime error arrayIList.Add(10); //Runs perfectly listIList.Add(10); }

En ambos casos cuando trato de agregar un nuevo valor, mi compilador no me da errores, pero obviamente el método que expone mi matriz como IList<T> da un error de tiempo de ejecución cuando intento agregarle algo. Por lo tanto, las personas que no saben lo que está sucediendo en mi método y tienen que agregarle valores, se ven obligadas a copiar primero mi IList a una List para poder agregar valores sin arriesgarse a cometer errores. Por supuesto, pueden hacer una verificación de tipo para ver si se trata de una List o una Array , pero si no lo hacen, y quieren agregar elementos a la colección, no tienen otra opción para copiar la IList a un List , incluso si ya es una List . ¿Una matriz nunca debe exponerse como IList ?

Otra preocupación mía se basa en la respuesta aceptada de la pregunta vinculada (énfasis mío):

Si está exponiendo su clase a través de una biblioteca que otros usarán, generalmente desea exponerla a través de interfaces en lugar de implementaciones concretas. Esto ayudará si decide cambiar la implementación de su clase más tarde para usar una clase concreta diferente. En ese caso, los usuarios de su biblioteca no necesitarán actualizar su código ya que la interfaz no cambia.

Si solo lo está utilizando internamente, es posible que no le importe tanto, y usar List puede estar bien.

Imagine que alguien realmente usara mi IList<T> que obtuvieron de mi método ExposeListIlist() simplemente para agregar / eliminar valores. Todo funciona bien Pero ahora, como sugiere la respuesta, dado que devolver una interfaz es más flexible, devuelvo una matriz en lugar de una Lista (¡no hay ningún problema de mi parte!), Entonces se van a tratar ...

TLDR:

1) ¿La exposición de una interfaz provoca lanzamientos innecesarios? ¿Eso no importa?

2) A veces, si los usuarios de la biblioteca no usan una conversión, su código puede romperse cuando cambias tu método, aunque el método permanezca perfectamente bien.

Probablemente estoy pensando demasiado en esto, pero no obtengo el consenso general de que devolver una interfaz es preferible a devolver una implementación.


Devolver una interfaz no es necesariamente mejor que devolver una implementación concreta de una colección. Siempre debe tener una buena razón para usar una interfaz en lugar de un tipo concreto. En su ejemplo, parece inútil hacerlo.

Las razones válidas para usar una interfaz pueden ser:

  1. No sabe cómo será la implementación de los métodos que devuelven la interfaz y puede haber muchos desarrollados a lo largo del tiempo. Pueden ser otras personas escribiéndolas, de otras compañías. Por lo tanto, solo desea ponerse de acuerdo sobre las necesidades básicas y dejarles a ellos cómo implementar la funcionalidad.

  2. Desea exponer algunas funciones comunes independientemente de su jerarquía de clases de una manera segura. Los objetos de diferentes tipos básicos que deberían ofrecer los mismos métodos implementarían su interfaz.

Se podría argumentar que 1 y 2 son básicamente la misma razón. Son dos escenarios diferentes que finalmente conducen a la misma necesidad.

"Es un contrato". Si el contrato es con usted y su aplicación está cerrada tanto en funcionalidad como en tiempo, a menudo no tiene sentido usar una interfaz.


Tal vez esto no responda directamente a su pregunta, pero en .NET 4.5+, prefiero seguir estas reglas al diseñar API públicas o protegidas:

  • devuelva IEnumerable<T> , si solo está disponible la enumeración;
  • devuelva IReadOnlyCollection<T> si tanto la enumeración como el recuento de elementos están disponibles;
  • devuelva IReadOnlyList<T> , si la enumeración, el recuento de elementos y el acceso indexado están disponibles;
  • devuelva ICollection<T> si la enumeración, el recuento de elementos y la modificación están disponibles;
  • devuelva IList<T> , si la enumeración, el recuento de elementos, el acceso indexado y la modificación están disponibles.

Las dos últimas opciones suponen que ese método no debe devolver la matriz como implementación IList<T> .


Tenga cuidado con las citas generales que se toman fuera de contexto.

Devolver una interfaz es mejor que devolver una implementación concreta

Esta cita solo tiene sentido si se usa en el contexto de los principios SÓLIDOS . Hay 5 principios, pero a los fines de esta discusión, hablaremos de los últimos 3.

Principio de inversión de dependencia

uno debe "depender de abstracciones. No dependas de concreciones.

En mi opinión, este principio es el más difícil de entender. Pero si miras la cita cuidadosamente, se parece mucho a tu cita original.

Depende de las interfaces (abstracciones). No dependa de implementaciones concretas (concreciones).

Esto sigue siendo un poco confuso, pero si comenzamos a aplicar los otros principios juntos, comenzará a tener mucho más sentido.

Principio de sustitución de Liskov

"Los objetos en un programa deben ser reemplazables con instancias de sus subtipos sin alterar la corrección de ese programa".

Como señaló, devolver una Array es un comportamiento claramente diferente a devolver una List<T> a pesar de que ambas implementan IList<T> . Esto es sin duda una violación de LSP.

Lo importante es darse cuenta de que las interfaces son sobre el consumidor . Si está devolviendo una interfaz, ha creado un contrato para que cualquier método o propiedad en esa interfaz pueda usarse sin cambiar el comportamiento del programa.

Principio de segregación de interfaz

"Muchas interfaces específicas del cliente son mejores que una interfaz de uso general".

Si está devolviendo una interfaz, debe devolver la interfaz más específica del cliente que su implementación admita. En otras palabras, si no espera que el cliente llame al método Add , no debe devolver una interfaz con un método Add .

Desafortunadamente, las interfaces en .NET Framework (particularmente las versiones anteriores) no siempre son interfaces ideales para clientes específicos. Aunque como señaló @Dennis en su respuesta, hay muchas más opciones en .NET 4.5+.


No, porque el consumidor debe saber qué es exactamente IList :

IList es un descendiente de la interfaz ICollection y es la interfaz base de todas las listas no genéricas. Las implementaciones de IList se dividen en tres categorías: solo lectura, tamaño fijo y tamaño variable. Una IList de solo lectura no se puede modificar. Una IList de tamaño fijo no permite la adición o eliminación de elementos, pero permite la modificación de elementos existentes. Una IList de tamaño variable permite la adición, eliminación y modificación de elementos.

Puede verificar IList.IsFixedSize e IList.IsReadOnly y hacer lo que quiera con él.

Creo que IList es un ejemplo de una interfaz gruesa y debería haberse dividido en varias interfaces más pequeñas y también viola el principio de sustitución de Liskov cuando devuelve una matriz como IList .

Lea más si desea tomar una decisión sobre la interfaz de retorno

ACTUALIZAR

Excavando más y descubrí que IList<T> no implementa IList e IsReadOnly es accesible a través de la interfaz base ICollection<T> pero no hay IsFixedSize para IList<T> . Lea más sobre por qué IList genérico <> no hereda IList no genérico.