Esa es una pregunta general (pero estoy usando C #), ¿cuál es la mejor manera (mejor práctica), ¿devuelve una colección nula o vacía para un método que tiene una colección como tipo de retorno?
c#
collections
Omu
fuente
fuente
Respuestas:
Colección vacía Siempre.
Esto apesta:
Se considera una práctica recomendada NUNCA regresar
null
al devolver una colección o enumerable. SIEMPRE devuelve una enumeración / colección vacía. Evita las tonterías antes mencionadas y evita que su auto sea incitado por compañeros de trabajo y usuarios de sus clases.Cuando hable de propiedades, siempre configure su propiedad una vez y olvídela
En .NET 4.6.1, puede condensar esto bastante:
Cuando se habla de métodos que devuelven enumerables, puede devolver fácilmente un enumerable vacío en lugar de
null
...Usar
Enumerable.Empty<T>()
puede verse como más eficiente que devolver, por ejemplo, una nueva colección o matriz vacía.fuente
IEnumerable
oICollection
no importa tanto. De todos modos, si seleccionas algo de tipoICollection
, también regresannull
... Me gustaría que devolvieran una colección vacía, pero me encontré con ellos regresandonull
, así que pensé en mencionarlo aquí. Yo diría que el valor predeterminado de una colección de enumerables es vacío, no nulo. No sabía que era un tema tan delicado.De las Directrices de diseño del marco, segunda edición (pág. 256):
Aquí hay otro artículo interesante sobre los beneficios de no devolver nulos (estaba tratando de encontrar algo en el blog de Brad Abram, y él lo vinculaba al artículo).
Editar: como Eric Lippert ha comentado la pregunta original, también me gustaría vincular a su excelente artículo .
fuente
Depende de su contrato y su caso concreto . En general , es mejor devolver colecciones vacías , pero a veces ( raramente ):
null
podría significar algo más específico;null
.Algunos ejemplos concretos:
null
significaría que falta el elemento, mientras que una colección vacía generaría una redundancia (y posiblemente incorrecta)<collection />
fuente
Hay otro punto que aún no se ha mencionado. Considere el siguiente código:
El lenguaje C # devolverá un enumerador vacío al llamar a este método. Por lo tanto, para ser coherente con el diseño del lenguaje (y, por lo tanto, con las expectativas del programador), debe devolverse una colección vacía.
fuente
Vacío es mucho más amigable para el consumidor.
Hay un método claro de hacer un enumerable vacío:
fuente
Me parece que debería devolver el valor semánticamente correcto en su contexto, sea lo que sea. Una regla que dice "siempre devolver una colección vacía" me parece un poco simplista.
Supongamos que, en un sistema para un hospital, tenemos una función que se supone que devuelve una lista de todas las hospitalizaciones anteriores de los últimos 5 años. Si el cliente no ha estado en el hospital, tiene sentido devolver una lista vacía. Pero, ¿qué pasa si el cliente deja en blanco esa parte del formulario de admisión? Necesitamos un valor diferente para distinguir "lista vacía" de "sin respuesta" o "no sé". Podríamos lanzar una excepción, pero no es necesariamente una condición de error, y no necesariamente nos saca del flujo normal del programa.
A menudo me han frustrado los sistemas que no pueden distinguir entre cero y ninguna respuesta. He tenido varias veces que un sistema me ha pedido que ingrese algún número, ingreso cero y recibo un mensaje de error que me dice que debo ingresar un valor en este campo. Acabo de hacerlo: ¡ingresé cero! Pero no aceptará cero porque no puede distinguirlo de ninguna respuesta.
Respuesta a Saunders:
Sí, supongo que hay una diferencia entre "La persona no respondió la pregunta" y "La respuesta fue cero". Ese fue el punto del último párrafo de mi respuesta. Muchos programas no pueden distinguir "no sabe" de en blanco o cero, lo que me parece una falla potencialmente grave. Por ejemplo, estaba comprando una casa hace aproximadamente un año. Fui a un sitio web de bienes raíces y había muchas casas listadas con un precio inicial de $ 0. A mí me pareció bastante bueno: ¡regalan estas casas gratis! Pero estoy seguro de que la triste realidad era que simplemente no habían ingresado el precio. En ese caso, usted puede decir: "Bueno, OBVIAMENTE cero significa que no ingresaron el precio, nadie va a regalar una casa gratis". Pero el sitio también enumeró los precios promedio de venta y solicitud de casas en varias ciudades. No puedo evitar preguntarme si el promedio no incluyó los ceros, lo que da un promedio incorrectamente bajo para algunos lugares. es decir, cuál es el promedio de $ 100,000; $ 120,000; y "no sabe"? Técnicamente, la respuesta es "no sé". Lo que probablemente realmente queremos ver es $ 110,000. Pero lo que probablemente obtendremos es $ 73,333, lo cual sería completamente incorrecto. Además, ¿qué pasaría si tuviéramos este problema en un sitio donde los usuarios pueden realizar pedidos en línea? (Es improbable para el sector inmobiliario, pero estoy seguro de que lo ha visto para muchos otros productos). ¿Realmente queremos que el "precio no especificado aún" se interprete como "gratis"? dando así un promedio incorrectamente bajo para algunos lugares. es decir, cuál es el promedio de $ 100,000; $ 120,000; y "no sabe"? Técnicamente, la respuesta es "no sé". Lo que probablemente realmente queremos ver es $ 110,000. Pero lo que probablemente obtendremos es $ 73,333, lo cual sería completamente incorrecto. Además, ¿qué pasaría si tuviéramos este problema en un sitio donde los usuarios pueden realizar pedidos en línea? (Es improbable para el sector inmobiliario, pero estoy seguro de que lo ha visto para muchos otros productos). ¿Realmente queremos que el "precio no especificado aún" se interprete como "gratis"? dando así un promedio incorrectamente bajo para algunos lugares. es decir, cuál es el promedio de $ 100,000; $ 120,000; y "no sabe"? Técnicamente, la respuesta es "no sé". Lo que probablemente realmente queremos ver es $ 110,000. Pero lo que probablemente obtendremos es $ 73,333, lo cual sería completamente incorrecto. Además, ¿qué pasaría si tuviéramos este problema en un sitio donde los usuarios pueden realizar pedidos en línea? (Es improbable para el sector inmobiliario, pero estoy seguro de que lo ha visto para muchos otros productos). ¿Realmente queremos que el "precio aún no especificado" se interprete como "gratis"? lo cual estaría completamente mal. Además, ¿qué pasaría si tuviéramos este problema en un sitio donde los usuarios pueden realizar pedidos en línea? (Es improbable para el sector inmobiliario, pero estoy seguro de que lo ha visto para muchos otros productos). ¿Realmente queremos que el "precio aún no especificado" se interprete como "gratis"? lo cual estaría completamente mal. Además, ¿qué pasaría si tuviéramos este problema en un sitio donde los usuarios pueden realizar pedidos en línea? (Es improbable para el sector inmobiliario, pero estoy seguro de que lo ha visto para muchos otros productos). ¿Realmente queremos que el "precio aún no especificado" se interprete como "gratis"?
RE tiene dos funciones separadas, un "¿hay alguna?" y un "si es así, ¿qué es?" Sí, ciertamente podrías hacer eso, pero ¿por qué quieres hacerlo? Ahora el programa de llamadas tiene que hacer dos llamadas en lugar de una. ¿Qué sucede si un programador no llama al "ninguno"? y va directamente al "¿qué es?" ? ¿El programa devolverá un cero erróneo? ¿Lanzar una excepción? ¿Devuelve un valor indefinido? Crea más código, más trabajo y más errores potenciales.
El único beneficio que veo es que le permite cumplir con una regla arbitraria. ¿Hay alguna ventaja en esta regla que haga que valga la pena obedecerla? Si no, ¿por qué molestarse?
Respuesta a Jammycakes:
Considere cómo se vería el código real. Sé que la pregunta decía C #, pero discúlpeme si escribo Java. Mi C # no es muy agudo y el principio es el mismo.
Con un retorno nulo:
Con una función separada:
En realidad, es una línea o dos códigos menos con el retorno nulo, por lo que no es más una carga para la persona que llama, es menos.
No veo cómo crea un problema SECO. No es que tengamos que ejecutar la llamada dos veces. Si siempre quisiéramos hacer lo mismo cuando la lista no existe, tal vez podríamos empujar el manejo hacia la función get-list en lugar de que la persona que llama lo haga, por lo que poner el código en la persona que llama sería una violación SECA. Pero casi seguro que no siempre queremos hacer lo mismo. En las funciones donde debemos tener la lista para procesar, una lista que falta es un error que bien podría detener el procesamiento. Pero en una pantalla de edición, seguramente no queremos detener el procesamiento si aún no han ingresado datos: queremos dejar que ingresen datos. Por lo tanto, el manejo de "no list" debe hacerse al nivel de la persona que llama de una forma u otra. Y si hacemos eso con un retorno nulo o una función separada, no hay diferencia para el principio más grande.
Claro, si la persona que llama no comprueba nulo, el programa podría fallar con una excepción de puntero nulo. Pero si hay una función separada "got any" y la persona que llama no llama a esa función sino que llama ciegamente a la función "get list", ¿qué sucede? Si arroja una excepción o falla, bueno, eso es más o menos lo que sucedería si devuelve nulo y no lo verifica. Si devuelve una lista vacía, eso está mal. No puede distinguir entre "Tengo una lista con cero elementos" y "No tengo una lista". Es como devolver cero por el precio cuando el usuario no ingresó ningún precio: simplemente está mal.
No veo cómo ayuda un atributo adicional a la colección. La persona que llama todavía tiene que verificarlo. ¿Cómo es eso mejor que verificar nulo? Una vez más, lo peor que puede pasar es que el programador olvide verificarlo y dar resultados incorrectos.
Una función que devuelve nulo no es una sorpresa si el programador está familiarizado con el concepto de nulo que significa "no tiene un valor", que creo que cualquier programador competente debería haber escuchado, ya sea que piense que es una buena idea o no. Creo que tener una función separada es más un problema "sorpresa". Si un programador no está familiarizado con la API, cuando ejecuta una prueba sin datos, descubrirá rápidamente que a veces recupera un valor nulo. Pero, ¿cómo descubriría la existencia de otra función a menos que se le ocurriera que podría existir tal función y verificara la documentación, y la documentación esté completa y sea comprensible? Preferiría tener una función que siempre me dé una respuesta significativa, en lugar de dos funciones que debo conocer y recordar llamar a ambas.
fuente
Si una colección vacía tiene sentido semánticamente, eso es lo que prefiero devolver. Devolver una colección vacía para
GetMessagesInMyInbox()
comunicar "realmente no tiene ningún mensaje en su bandeja de entrada", mientras que devolvernull
puede ser útil para comunicar que no hay suficientes datos disponibles para decir cómo debería ser la lista que se devolverá.fuente
null
valor seguramente no parece razonable, estaba pensando en términos más generales al respecto. Las excepciones también son excelentes para comunicar el hecho de que algo ha salido mal, pero si los "datos insuficientes" a los que se hace referencia son perfectamente esperados, entonces lanzar una excepción sería un mal diseño. Estoy pensando en un escenario en el que es perfectamente posible y no hay ningún error para que el método a veces no pueda calcular una respuesta.Devolver nulo podría ser más eficiente, ya que no se crea ningún objeto nuevo. Sin embargo, a menudo también requeriría un
null
verificación (o manejo de excepciones).Semánticamente
null
y una lista vacía no significa lo mismo. Las diferencias son sutiles y una opción puede ser mejor que la otra en casos específicos.Independientemente de su elección, documente para evitar confusiones.
fuente
Se podría argumentar que el razonamiento detrás del Patrón de objetos nulos es similar a uno a favor de devolver la colección vacía.
fuente
Depende de la situación. Si es un caso especial, devuelva nulo. Si la función simplemente devuelve una colección vacía, entonces, obviamente, devolver eso está bien. Sin embargo, devolver una colección vacía como un caso especial debido a parámetros no válidos u otras razones NO es una buena idea, ya que está enmascarando una condición de caso especial.
En realidad, en este caso, generalmente prefiero lanzar una excepción para asegurarme de que REALMENTE no se ignore :)
Decir que hace que el código sea más robusto (al devolver una colección vacía) ya que no tienen que manejar la condición nula es malo, ya que simplemente está enmascarando un problema que debe ser manejado por el código de llamada.
fuente
Yo diría que eso
null
no es lo mismo que una colección vacía y debe elegir cuál representa mejor lo que está devolviendo. En la mayoría de los casosnull
es nada (excepto en SQL). Una colección vacía es algo, aunque sea algo vacío.Si tiene que elegir uno u otro, diría que debe tender a una colección vacía en lugar de nula. Pero hay momentos en que una colección vacía no es lo mismo que un valor nulo.
fuente
Piense siempre a favor de sus clientes (que están usando su API):
Devolver 'nulo' muy a menudo causa problemas con los clientes que no manejan las verificaciones nulas correctamente, lo que provoca una NullPointerException durante el tiempo de ejecución. He visto casos en los que la falta de verificación nula forzó un problema de producción prioritario (un cliente usó foreach (...) en un valor nulo). Durante las pruebas, el problema no se produjo porque los datos operados eran ligeramente diferentes.
fuente
Me gusta dar explicaciones aquí, con un ejemplo adecuado.
Considere un caso aquí ...
Aquí considere las funciones que estoy usando.
Puedo usar fácilmente
ListCustomerAccount
y enFindAll
lugar de.NOTA: Dado que AccountValue no lo es
null
, la función Sum () no regresaránull
. Por lo tanto, puedo usarla directamente.fuente
Tuvimos esta discusión entre el equipo de desarrollo en el trabajo hace una semana más o menos, y casi unánimemente fuimos por la recolección vacía. Una persona quería devolver nulo por la misma razón que Mike especificó anteriormente.
fuente
Colección vacía Si está utilizando C #, se supone que maximizar los recursos del sistema no es esencial. Si bien es menos eficiente, devolver la colección vacía es mucho más conveniente para los programadores involucrados (por la razón que Will describió anteriormente).
fuente
Devolver una colección vacía es mejor en la mayoría de los casos.
La razón de esto es la conveniencia de la implementación de la persona que llama, un contrato consistente y una implementación más fácil.
Si un método devuelve nulo para indicar un resultado vacío, la persona que llama debe implementar un adaptador de comprobación nulo además de la enumeración. Este código se duplica en varias personas que llaman, así que ¿por qué no poner este adaptador dentro del método para que pueda reutilizarse?
Un uso válido de nulo para IEnumerable puede ser una indicación de resultado ausente o un fallo de la operación, pero en este caso se deben considerar otras técnicas, como lanzar una excepción.
fuente
Vea aquí para una tormenta de mierda elaborada
null
en general. No estoy de acuerdo con la afirmación de queundefined
es otranull
, pero aún vale la pena leerla. Y explica por qué debería evitarlonull
y no solo en el caso de que lo haya pedido. La esencia es que,null
en cualquier idioma, es un caso especial. Tienes que pensarnull
como una excepción.undefined
es diferente en ese sentido, ese código que trata con comportamientos indefinidos es en la mayoría de los casos solo un error C y la mayoría de los otros lenguajes también tienen un comportamiento indefinido, pero la mayoría de ellos no tienen un identificador para eso en el lenguaje.fuente
Desde la perspectiva de la gestión de la complejidad, un objetivo principal de ingeniería de software, queremos evitar la propagación innecesaria la complejidad ciclomática a los clientes de una API. Devolver un valor nulo al cliente es como devolverle el costo de complejidad ciclomática de otra rama de código.
(Esto corresponde a una carga de prueba unitaria. Debería escribir una prueba para el caso de devolución nulo, además del caso de devolución de colección vacía).
fuente