Pregunta

¿Cuál es la mejor práctica cuando se devuelven datos de funciones? ¿Es mejor devolver un objeto nulo o vacío? ¿Y por qué debería uno hacer uno sobre el otro?

Considera esto:

public UserEntity GetUserById(Guid userId)
{
     //Imagine some code here to access database.....

     //Check if data was returned and return a null if none found
     if (!DataExists)
        return null; 
        //Should I be doing this here instead? 
        //return new UserEntity();  
     else
        return existingUserEntity;
}

Supongamos que habría casos válidos en este programa y que no habría información de usuario en la base de datos con ese GUID. Me imagino que no sería apropiado lanzar una excepción en este caso. También tengo la impresión de que el manejo de excepciones puede afectar el rendimiento.

¿Fue útil?

Solución

Devolver nulo suele ser la mejor idea si tiene la intención de indicar que no hay datos disponibles.

Un objeto vacío implica que se han devuelto datos, mientras que devolver nulo indica claramente que no se ha devuelto nada.

Además, devolver un valor nulo dará como resultado una excepción nula si intenta acceder a los miembros en el objeto, lo que puede ser útil para resaltar el código defectuoso; intentar acceder a un miembro de la nada no tiene sentido. El acceso a los miembros de un objeto vacío no fallará, lo que significa que los errores pueden quedar sin descubrir.

Otros consejos

Depende de lo que tenga más sentido para su caso.

¿Tiene sentido devolver nulo, p. " no existe tal usuario " ;?

¿O tiene sentido crear un usuario predeterminado? Esto tiene más sentido cuando puede asumir con seguridad que si un usuario NO existe, el código de llamada intenta que exista uno cuando lo solicite.

¿O tiene sentido lanzar una excepción (a la " FileNotFound ") si el código de llamada exige un usuario con una ID no válida?

Sin embargo, desde una separación de preocupaciones / punto de vista de SRP, los dos primeros son más correctos. Y técnicamente el primero es el más correcto (pero solo por un pelo): GetUserById solo debería ser responsable de una cosa: obtener al usuario. Manejar su propio " usuario no existe " el caso al devolver algo más podría ser una violación de SRP. Separar en una comprobación diferente: bool DoesUserExist (id) sería apropiado si elige lanzar una excepción.

Basado en los extensos comentarios a continuación : si esta es una pregunta de diseño a nivel API, este método podría ser análogo a "OpenFile" o "ReadEntireFile". Estamos " abriendo " un usuario de algún repositorio e hidratando el objeto a partir de los datos resultantes. Una excepción podría ser apropiada en este caso. Puede que no sea, pero podría ser.

Todos los enfoques son aceptables, solo depende, en función del contexto más amplio de la API / aplicación.

Personalmente, uso NULL. Deja en claro que no hay datos para devolver. Pero hay casos en que un Objeto nulo puede ser útil.

Si su tipo de retorno es una matriz, devuelva una matriz vacía; de lo contrario, devuelva nulo.

Debería lanzar una excepción (solo) si se rompe un contrato específico.
En su ejemplo específico, solicitar una entidad de usuario basada en un Id conocido, dependería del hecho si los usuarios faltantes (eliminados) son un caso esperado. Si es así, entonces devuelve null pero si no es un caso esperado, arroje una excepción.
Tenga en cuenta que si la función se llamara UserEntity GetUserByName (string name) , probablemente no arrojaría sino que devolvería nulo. En ambos casos, devolver una UserEntity vacía sería inútil.

Para cadenas, matrices y colecciones, la situación suele ser diferente. Recuerdo algunas pautas de MS que los métodos deberían aceptar null como una lista 'vacía' pero devolver colecciones de longitud cero en lugar de null . Lo mismo para las cuerdas. Tenga en cuenta que puede declarar matrices vacías: int [] arr = new int [0];

Esta es una pregunta comercial, que depende de si la existencia de un usuario con un Id. de Guid específico es un caso de uso normal esperado para esta función, o es una anomalía que evitará que la aplicación complete con éxito cualquier función que este método sea proporcionando el objeto de usuario a ...

Si se trata de una "excepción", ya que la ausencia de un usuario con ese Id evitará que la aplicación complete con éxito cualquier función que esté realizando (supongamos que estamos creando una factura para un cliente al que le hemos enviado el producto) a ...), entonces esta situación debería generar una excepción ArgumentException (o alguna otra excepción personalizada).

Si un usuario perdido está bien (uno de los posibles resultados normales de llamar a esta función), entonces devuelve un valor nulo ...

EDITAR: (para abordar el comentario de Adam en otra respuesta)

Si la aplicación contiene múltiples procesos de negocios, uno o más de los cuales requieren un Usuario para completar con éxito, y uno o más de los cuales pueden completarse exitosamente sin un usuario, entonces la excepción se debe lanzar más arriba en la pila de llamadas, más cerca de donde los procesos de negocio que requieren un Usuario están llamando a este hilo de ejecución. Los métodos entre este método y ese punto (donde se está lanzando la excepción) solo deben comunicar que no existe ningún usuario (nulo, booleano, lo que sea; este es un detalle de implementación).

Pero si todos los procesos dentro de la aplicación requieren un usuario, aún arrojaría la excepción en este método ...

Personalmente, devolvería nulo, porque así es como esperaría que actúe la capa DAL / Repository.

Si no existe, no devuelva nada que pueda interpretarse como recuperar un objeto con éxito, null funciona muy bien aquí.

Lo más importante es ser consistente a través de su capa DAL / Repos, de esa manera no se confunda sobre cómo usarlo.

tiendo a

  • return null si la identificación del objeto no existe cuando no se sabe de antemano si debería existir.
  • throw si la identificación del objeto no existe cuando debería existir.

Distingo estos dos escenarios con estos tres tipos de métodos. Primero:

Boolean TryGetSomeObjectById(Int32 id, out SomeObject o)
{
    if (InternalIdExists(id))
    {
        o = InternalGetSomeObject(id);

        return true;
    }
    else
    {
        return false;
    }
}

Segundo:

SomeObject FindSomeObjectById(Int32 id)
{
    SomeObject o;

    return TryGetObjectById(id, out o) ? o : null;
}

Tercero:

SomeObject GetSomeObjectById(Int32 id)
{
    SomeObject o;

    if (!TryGetObjectById(id, out o))
    {
        throw new SomeAppropriateException();
    }

    return o;
}

Sin embargo, otro enfoque implica pasar un objeto de devolución de llamada o delegado que operará en el valor. Si no se encuentra un valor, no se llama a la devolución de llamada.

public void GetUserById(Guid id, UserCallback callback)
{
    // Lookup user
    if (userFound)
        callback(userEntity);  // or callback.Call(userEntity);
}

Esto funciona bien cuando desea evitar verificaciones nulas en todo su código, y cuando no encuentra un valor no es un error. También puede proporcionar una devolución de llamada para cuando no se encuentren objetos si necesita un procesamiento especial.

public void GetUserById(Guid id, UserCallback callback, NotFoundCallback notFound)
{
    // Lookup user
    if (userFound)
        callback(userEntity);  // or callback.Call(userEntity);
    else
        notFound(); // or notFound.Call();
}

El mismo enfoque con un solo objeto podría verse así:

public void GetUserById(Guid id, UserCallback callback)
{
    // Lookup user
    if (userFound)
        callback.Found(userEntity);
    else
        callback.NotFound();
}

Desde una perspectiva de diseño, me gusta mucho este enfoque, pero tiene la desventaja de hacer que el sitio de llamadas sea más voluminoso en idiomas que no admiten funciones de primera clase.

Usamos CSLA.NET, y considera que una recuperación de datos fallida debería devolver un " vacío " objeto. Esto es realmente bastante molesto, ya que exige la convención de verificar si obj.IsNew en lugar de obj == null .

Como se mencionó en un póster anterior, los valores de retorno nulos harán que el código falle inmediatamente, reduciendo la probabilidad de problemas de sigilo causados ??por objetos vacíos.

Personalmente, creo que null es más elegante.

Es un caso muy común, y me sorprende que la gente aquí parezca sorprendida por él: en cualquier aplicación web, los datos a menudo se obtienen utilizando un parámetro de cadena de consulta, que obviamente puede ser alterado, por lo que requiere que el desarrollador maneje las incidencias de " no encontrado " ;.

Puede manejar esto:

if (User.Exists(id)) {
  this.User = User.Fetch(id);
} else {
  Response.Redirect("~/notfound.aspx");
}

... pero esa es una llamada adicional a la base de datos cada vez, lo que puede ser un problema en las páginas de alto tráfico. Considerando que:

this.User = User.Fetch(id);

if (this.User == null) {
  Response.Redirect("~/notfound.aspx");
}

... requiere solo una llamada.

Prefiero null , ya que es compatible con el operador de fusión nula ( ?? ).

Yo diría que devuelve nulo en lugar de un objeto vacío.

Pero la instancia específica que ha mencionado aquí, está buscando un usuario por ID de usuario, que es ordenar de la clave para ese usuario, en ese caso probablemente querría para lanzar una excepción si no hay una instancia de instancia de usuario encontró.

Esta es la regla que generalmente sigo:

  • Si no se encuentra ningún resultado en una operación de búsqueda por clave primaria, lanzar ObjectNotFoundException.
  • Si no se encuentra ningún resultado en un hallazgo por ningún otro criterio, volver nulo.
  • Si no se encuentra ningún resultado en un hallazgo por un criterio no clave que puede devolver varios objetos devolver una colección vacía.

Varía según el contexto, pero generalmente devolveré nulo si busco un objeto en particular (como en su ejemplo) y devolveré una colección vacía si busco un conjunto de objetos pero no hay ninguno .

Si ha cometido un error en su código y devuelve valores nulos que conducen a excepciones de puntero nulo, cuanto antes lo detecte, mejor. Si devuelve un objeto vacío, el uso inicial puede funcionar, pero puede obtener errores más tarde.

Lo mejor en este caso devuelve " nulo " en un caso no existe tal usuario. También haga que su método sea estático.

Editar:

Por lo general, métodos como este son miembros de algún " Usuario " clase y no tienen acceso a sus miembros de instancia. En este caso, el método debe ser estático; de lo contrario, debe crear una instancia de " Usuario " y luego llame al método GetUserById que devolverá otro '' Usuario '' ejemplo. De acuerdo, esto es confuso. Pero si el método GetUserById es miembro de alguna " DatabaseFactory " clase: no hay problema para dejarlo como miembro de la instancia.

Yo personalmente devuelvo una instancia predeterminada del objeto. La razón es que espero que el método devuelva cero a muchos o cero a uno (dependiendo del propósito del método). La única razón por la que sería un estado de error de cualquier tipo, usando este enfoque, es si el método no devolvió ningún objeto (s) y siempre se esperaba que (en términos de uno a muchos o retorno singular).

En cuanto a la suposición de que esta es una pregunta de dominio comercial, simplemente no la veo desde ese lado de la ecuación. La normalización de los tipos de retorno es una pregunta válida de arquitectura de la aplicación. Como mínimo, está sujeto a estandarización en las prácticas de codificación. Dudo que haya un usuario de negocios que diga "en el escenario X, simplemente déle un nulo".

En nuestros Business Objects tenemos 2 métodos principales de obtención:

Para mantener las cosas simples en el contexto o si cuestionas, serían:

// Returns null if user does not exist
public UserEntity GetUserById(Guid userId)
{
}

// Returns a New User if user does not exist
public UserEntity GetNewOrExistingUserById(Guid userId)
{
}

El primer método se usa al obtener entidades específicas, el segundo método se usa específicamente al agregar o editar entidades en páginas web.

Esto nos permite tener lo mejor de ambos mundos en el contexto en el que se usan.

Soy un estudiante francés de informática, así que disculpe mi pobre inglés. En nuestras clases se nos dice que dicho método nunca debe devolver nulo, ni un objeto vacío. Se supone que el usuario de este método debe verificar primero que el objeto que está buscando existe antes de intentar obtenerlo.

Usando Java, se nos pide que agreguemos una afirmar que existe (objeto): " No debe intentar acceder a un objeto que no existe " ;; al comienzo de cualquier método que podría devolver nulo, para expresar la "condición previa" (No sé cuál es la palabra en inglés).

En mi opinión, esto no es realmente fácil de usar, pero eso es lo que estoy usando, esperando algo mejor.

Si el caso del usuario que no se encuentra aparece con la frecuencia suficiente, y desea lidiar con eso de varias maneras dependiendo de las circunstancias (a veces lanzando una excepción, a veces sustituyendo a un usuario vacío), también podría usar algo cercano a F # 's Option o el tipo Quizás de Haskell, que separa explícitamente el caso 'sin valor' de '¡encontró algo!'. El código de acceso a la base de datos podría verse así:

public Option<UserEntity> GetUserById(Guid userId)
{
 //Imagine some code here to access database.....

 //Check if data was returned and return a null if none found
 if (!DataExists)
    return Option<UserEntity>.Nothing; 
 else
    return Option.Just(existingUserEntity);
}

Y se usa así:

Option<UserEntity> result = GetUserById(...);
if (result.IsNothing()) {
    // deal with it
} else {
    UserEntity value = result.GetValue();
}

Desafortunadamente, todo el mundo parece tener un tipo como este.

Normalmente devuelvo nulo. Proporciona un mecanismo rápido y fácil para detectar si algo se estropeó sin lanzar excepciones y usar toneladas de try / catch en todo el lugar.

Para los tipos de colección, devolvería una Colección vacía, para todos los demás tipos, prefiero usar los patrones de NullObject para devolver un objeto que implemente la misma interfaz que la del tipo de retorno. para obtener detalles sobre el patrón, consulte texto del enlace

Usando el patrón NullObject esto sería: -

public UserEntity GetUserById(Guid userId)

{      // Imagina un código aquí para acceder a la base de datos .....

 //Check if data was returned and return a null if none found
 if (!DataExists)
    return new NullUserEntity(); //Should I be doing this here instead? return new UserEntity();  
 else
    return existingUserEntity;

}

class NullUserEntity: IUserEntity { public string getFirstName(){ return ""; } ...} 

Para decir lo que otros han dicho de una manera más concisa ...

Las excepciones son para circunstancias excepcionales

Si este método es pura capa de acceso a datos, diría que dado algún parámetro que se incluye en una instrucción select, esperaría que no encuentre ninguna fila desde la cual construir un objeto, y por lo tanto, devolver nulo sería aceptable ya que esta es la lógica de acceso a datos.

Por otro lado, si esperaba que mi parámetro reflejara una clave primaria y solo debería recuperar una fila, si obtuviera más de una, arrojaría una excepción. 0 está bien para devolver nulo, 2 no lo está.

Ahora, si tuviera algún código de inicio de sesión que verificara con un proveedor LDAP y luego verificara con una base de datos para obtener más detalles y esperaba que deberían estar sincronizados en todo momento, podría arrojar la excepción en ese momento. Como otros dijeron, son las reglas de negocios.

Ahora diré que es una regla general . Hay momentos en los que es posible que desee romper eso. Sin embargo, mi experiencia y experimentos con C # (mucho de eso) y Java (un poco de eso) me han enseñado que es mucho un rendimiento más costoso para manejar excepciones que para manejar problemas predecibles a través de condiciones lógica. Estoy hablando con la melodía de 2 o 3 órdenes de magnitud más cara en algunos casos. Entonces, si es posible, su código podría terminar en un bucle, entonces recomendaría devolver nulo y probarlo.

Perdona mi pseudo-php / código.

Creo que realmente depende del uso previsto del resultado.

Si tiene la intención de editar / modificar el valor de retorno y guardarlo, devuelva un objeto vacío. De esa manera, puede usar la misma función para llenar datos en un objeto nuevo o existente.

Digamos que tengo una función que toma una clave primaria y una matriz de datos, llena la fila con datos y luego guarda el registro resultante en la base de datos. Como tengo la intención de llenar el objeto con mis datos de cualquier manera, puede ser una gran ventaja recuperar un objeto vacío del getter. De esa manera, puedo realizar operaciones idénticas en cualquier caso. Utiliza el resultado de la función getter sin importar qué.

Ejemplo:

function saveTheRow($prim_key, $data) {
    $row = getRowByPrimKey($prim_key);

    // Populate the data here

    $row->save();
}

Aquí podemos ver que la misma serie de operaciones manipula todos los registros de este tipo.

Sin embargo, si la intención final del valor de retorno es leer y hacer algo con los datos, entonces devolvería nulo. De esta manera, puedo determinar rápidamente si no se devolvieron datos y mostrar el mensaje apropiado al usuario.

Por lo general, detectaré excepciones en mi función que recupera los datos (para poder registrar mensajes de error, etc.) y luego devolver nulo directamente desde el catch. Por lo general, no le importa al usuario final cuál es el problema, por lo que creo que es mejor encapsular mi registro / procesamiento de errores directamente en la función que obtiene los datos. Si mantiene una base de código compartida en cualquier empresa grande, esto es especialmente beneficioso porque puede forzar el registro / manejo de errores adecuado incluso en el programador más vago.

Ejemplo:

function displayData($row_id) {
    // Logging of the error would happen in this function
    $row = getRow($row_id);
    if($row === null) {
        // Handle the error here
    }

    // Do stuff here with data
}

function getRow($row_id) {
 $row = null;
 try{
     if(!$db->connected()) {
   throw excpetion("Couldn't Connect");
  }

  $result = $db->query($some_query_using_row_id);

  if(count($result) == 0 ) {
   throw new exception("Couldn't find a record!");
  }

  $row = $db->nextRow();

 } catch (db_exception) {
  //Log db conn error, alert admin, etc...
  return null; // This way I know that null means an error occurred
 }
 return $row;
}

Esa es mi regla general. Ha funcionado bien hasta ahora.

Pregunta interesante y creo que no hay "correcto" respuesta, ya que siempre depende de la responsabilidad de su código. ¿Su método sabe si los datos encontrados no son un problema o no? En la mayoría de los casos, la respuesta es "no". y es por eso que volver nulo y dejar que la persona que llama maneje la situación sea perfecta.

Quizás un buen enfoque para distinguir los métodos de lanzamiento de los métodos de retorno nulo es encontrar una convención en su equipo: Métodos que digan que "obtienen". algo debería arrojar una excepción si no hay nada que obtener. Los métodos que pueden devolver nulo podrían denominarse de manera diferente, tal vez "Buscar ..." en su lugar.

Si el objeto devuelto es algo que se puede iterar, devolvería un objeto vacío, para no tener que probar primero nulo.

Ejemplo:

bool IsAdministrator(User user)
{
    var groupsOfUser = GetGroupsOfUser(user);

    // This foreach would cause a run time exception if groupsOfUser is null.
    foreach (var groupOfUser in groupsOfUser) 
    {
        if (groupOfUser.Name == "Administrators")
        {
            return true;
        }
    }

    return false;
}

Me gusta no devolver nulo de ningún método, sino usar el tipo funcional Opción en su lugar. Los métodos que no pueden devolver ningún resultado devuelven una opción vacía, en lugar de nula.

Además, los métodos que no pueden devolver ningún resultado deberían indicarlo a través de su nombre. Normalmente pongo Try o TryGet o TryFind al comienzo del nombre del método para indicar que puede devolver un resultado vacío (por ejemplo, TryFindCustomer, TryLoadFile, etc.).

Eso permite a la persona que llama aplicar diferentes técnicas, como la canalización de la colección (consulte Martina Fowler Canalización de la colección ) en el resultado.

Aquí hay otro ejemplo donde se usa la opción de devolución en lugar de nulo para reducir la complejidad del código: Cómo reducir la complejidad ciclomática: Opción Tipo funcional

Más carne para moler: digamos que mi DAL devuelve un NULL para GetPersonByID según lo aconsejado por algunos. ¿Qué debe hacer mi BLL (más bien delgado) si recibe un NULL? ¿Pasar ese NULL y dejar que el consumidor final se preocupe por ello (en este caso, una página ASP.Net)? ¿Qué tal si el BLL lanza una excepción?

ASP.Net y Win App, u otra biblioteca de clase, pueden estar utilizando BLL, creo que es injusto esperar que el consumidor final intrínsecamente "sepa". que el método GetPersonByID devuelve un valor nulo (a menos que se usen tipos nulos, supongo).

Mi opinión (por lo que vale) es que mi DAL devuelve NULL si no se encuentra nada. PARA ALGUNOS OBJETOS, está bien, podría ser un 0: muchas listas de cosas, por lo que no tener nada está bien (por ejemplo, una lista de libros favoritos). En este caso, mi BLL devuelve una lista vacía. Para la mayoría de las cosas de una sola entidad (por ejemplo, usuario, cuenta, factura) si no tengo una, entonces definitivamente es un problema y una excepción costosa. Sin embargo, dado que recuperar un usuario mediante un identificador único que la aplicación ha proporcionado previamente siempre debe devolver un usuario, la excepción es un "correcto". excepción, ya que es excepcional. El consumidor final de BLL (ASP.Net, f'rinstance) solo espera que las cosas sean muy buenas, por lo que se usará un controlador de excepciones no manejadas en lugar de ajustar cada llamada a GetPersonByID en un bloque try - catch.

Si hay un problema evidente en mi enfoque, avíseme ya que siempre estoy ansioso por aprender. Como han dicho otros carteles, las excepciones son cosas costosas, y el "comprobar primero" el enfoque es bueno, pero las excepciones deberían ser solo eso: excepcional.

Estoy disfrutando esta publicación, muchas buenas sugerencias para "depende" escenarios :-)

Creo que las funciones no deberían devolver nulo, por la salud de su base de código. Se me ocurren algunas razones:

Habrá una gran cantidad de cláusulas de protección que tratan la referencia nula if (f ()! = null) .

¿Qué es null , es una respuesta aceptada o un problema? ¿Es nulo un estado válido para un objeto específico? (imagina que eres un cliente para el código). Quiero decir que todos los tipos de referencia pueden ser nulos, pero ¿deberían?

Tener null dando vueltas casi siempre dará algunas excepciones inesperadas de NullRef de vez en cuando a medida que crece su base de código.

Hay algunas soluciones, patrón probador-hacedor o implementar el tipo de opción desde la programación funcional.

Estoy perplejo ante la cantidad de respuestas (en toda la web) que dicen que necesita dos métodos: un " IsItThere () " método y un " GetItForMe () " método y esto lleva a una condición de carrera. ¿Qué hay de malo en una función que devuelve nulo, asignándola a una variable y verificando la variable para Nulo todo en una prueba? Mi antiguo código C estaba salpicado de

if (NULL! = (variable = function (argumentos ...))) {

Entonces obtienes el valor (o nulo) en una variable y el resultado de una vez. ¿Se ha olvidado este idioma? ¿Por qué?

Estoy de acuerdo con la mayoría de las publicaciones aquí, que tienden hacia null .

Mi razonamiento es que generar un objeto vacío con propiedades no anulables puede causar errores. Por ejemplo, una entidad con una propiedad int ID tendría un valor inicial de ID = 0 , que es un valor completamente válido. Si ese objeto, bajo alguna circunstancia, se guarda en la base de datos, sería algo malo.

Para cualquier cosa con un iterador, siempre usaría la colección vacía. Algo como

foreach (var eachValue in collection ?? new List<Type>(0))

es código olor en mi opinión. Las propiedades de la colección no deberían ser nulas, nunca.

Un caso de borde es String . Mucha gente dice que String.IsNullOrEmpty no es realmente necesario, pero no siempre se puede distinguir entre una cadena vacía y una nula. Además, algunos sistemas de bases de datos (Oracle) no distinguirán entre ellos ( '' se almacena como DBNULL ), por lo que se ve obligado a manejarlos por igual. La razón de esto es que la mayoría de los valores de cadena provienen de la entrada del usuario o de sistemas externos, mientras que ni los cuadros de texto ni la mayoría de los formatos de intercambio tienen representaciones diferentes para '' y null . Entonces, incluso si el usuario desea eliminar un valor, no puede hacer nada más que borrar el control de entrada. Además, la distinción de campos de base de datos nvarchar anulables y no anulables es más que cuestionable, si su DBMS no es oráculo: un campo obligatorio que permite que '' sea extraño, su IU nunca permitiría esto, por lo que sus restricciones no se asignan. Entonces la respuesta aquí, en mi opinión es, manejarlos por igual, siempre.

Con respecto a su pregunta sobre excepciones y rendimiento: Si lanzas una excepción que no puedes manejar completamente en la lógica de tu programa, tienes que abortar, en algún momento, lo que sea que esté haciendo tu programa, y ??pedirle al usuario que vuelva a hacer lo que acaba de hacer. En ese caso, la penalización de rendimiento de un catch es realmente la menor de sus preocupaciones: tener que preguntarle al usuario es el elefante en la habitación (lo que significa volver a representar toda la interfaz de usuario o enviar algo de HTML a través de Internet). Entonces, si no sigue el antipatrón de " Flujo de programa con excepciones " ;, no te molestes, solo tira uno si tiene sentido. Incluso en casos límite, como "Excepción de validación", el rendimiento realmente no es un problema, ya que debe preguntar al usuario nuevamente, en cualquier caso.

Un patrón asincrónico TryGet:

Para métodos sincrónicos, creo que @Johann Gerell's answer es el patrón para usar en todos los casos.

Sin embargo, el patrón TryGet con el parámetro out no funciona con los métodos Async.

Con Tuple Literals de C # 7 ahora puede hacer esto:

async Task<(bool success, SomeObject o)> TryGetSomeObjectByIdAsync(Int32 id)
{
    if (InternalIdExists(id))
    {
        o = await InternalGetSomeObjectAsync(id);

        return (true, o);
    }
    else
    {
        return (false, default(SomeObject));
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top