2011-05-07 20 views
5

uso propiedades genéricas en mi proyecto, pero no sé, ¿hay alguna desventaja de usarlas, por favor díganme un escenario, tienen una desventaja? Mi parte del código a continuación.¿Desventajas genéricas de la propiedad?

public class GenericResult<T> 
{ 
    public T Data { get; set; } 
    public bool IsSuccess { get; set; } 
    public string Message { get; set; } 
} 

public GenericResult<int> AddCategory(TCategory tCategory) 
{ 
    GenericResult<int> result = new GenericResult<int>(); 

    //business logic validation,dont make sense,only example :) 
    if (tCategory.Name.Lenght > 100) 
    { 
     result.IsSuccess = false; 
     result.Message = "Category Name length is too long"; 
     result.Data = 0; 
    } 

    //handle .net runtime error//may be database is not aviable. 
    try 
    { 
     result.Data = this.catalogRepository.AddCategory(tCategory); 
     result.IsSuccess = true; 
    } 
    catch (Exception ex) 
    { 
     result.Data = 0; 
     result.IsSuccess = false; 
     result.Message = ex.Message; 
    } 
    return result; 
} 

public GenericResult<IEnumerable<TCategory>> GetCategoryHierarchy(TCategory parentCategory) 
{ 
    GenericResult<IEnumerable<TCategory>> result = new GenericResult<IEnumerable<TCategory>>(); 
    try 
    { 
     IEnumerable<TCategory> allCategories = catalogRepository.GetAllCategories(); 
     result.Data = GetCategoryHierarchy(allCategories, parentCategory); 
     result.IsSuccess = true; 

    } 
    catch (Exception ex) 
    { 
     result.IsSuccess = false; 
     result.Data = null; 
     result.Message = ex.Message; 
    } 
    return result; 
} 
+0

si AddCategory falla, ¿por qué devuelve una instancia? esto generalmente se considera una mala práctica. devuelve nulo para que sea claramente visible desde el exterior que algo falló. –

+0

De acuerdo con Mario, ¡pero lanzar una excepción podría ser más expresivo para mostrar a todos que algo salió mal! – renatoargh

+1

'null' no le da ningún mensaje. Lo que está devolviendo es una versión casera de un 'MayBe ' que es un buen patrón en otros idiomas. – CodesInChaos

Respuesta

4

Si no desea lanzar una excepción, pero prefiere devolver un resultado que contenga el error o el valor, es decir, un MayBe que está bien en algunas situaciones. Pero para ser honesto en esta situación, preferiría simplemente lanzar/pasar por la excepción.

Preferiría devolver una estructura inmutable como MayBe en lugar de una clase mutable como la que hizo. Es muy similar al Nullable<T>, excepto que funciona en tipos de referencia y puede almacenar un error. Algo así como:

public struct MayBe<T> 
{ 
    private T value; 
    private Exception error; 

    public bool HasValue{get{return error==null;}} 
    public T Value 
    { 
     if(error!=null) 
     throw error; 
     else 
     return value; 
    } 

    public static MayBe<T> CreateError(Exception exception) 
    { 
     return new MayBe<T>(default(T),exception); 
    } 

    public static MayBe<T> CreateValue(T value) 
    { 
     return new MayBe<T>(value,null); 
    } 

    public static implicit operator MayBe<T>(T value) 
    { 
     return CreateValue(value); 
    } 

    public override string ToString() 
    { 
     if(HasValue) 
      return "Value: "+Value.ToString(); 
     else 
      return "Error: "+Error.GetType().Name+" "+Error.Message; 
    } 
} 

Su código se convierte en

public MayBe<int> AddCategory(TCategory tCategory) 
{ 
    try 
    { 
     return this.catalogRepository.AddCategory(tCategory); 
    } 
    catch (Exception ex) 
    { 
     return MayBe<int>.CreateError(ex); 
    } 

    return result; 
} 

public MayBe<IEnumerable<TCategory>> GetCategoryHierarchy(TCategory parentCategory) 
{ 
    try 
    { 
     IEnumerable<TCategory> allCategories = catalogRepository.GetAllCategories(); 
     return allCategories; 

    } 
    catch (Exception ex) 
    { 
     return MayBe<int>.CreateError(ex); 
    } 

    return result; 
} 

Un problema que veo con esta implementación es que las excepciones no son completamente inmutable. Eso puede causar problemas si el mismo MayBe<T> arroja múltiples hilos. Quizás alguien pueda sugerir una mejor implementación.

+0

¿Por qué 'struct'? (simplemente curioso) – abatishchev

+0

Porque 1) No puede ser' nulo'. Ya que manejamos valores 'null' internamente teniendo todo el' MayBe' como 'null' no tiene mucho sentido 2) Es barato. Tiene solo dos campos. 3) Como es inmutable, casi no existen diferencias semánticas aparte de la capacidad de anulación. – CodesInChaos

0

El uso de la propiedad automática es bastante bueno y no veo ningún problema.

Pero desafío fuertemente el patrón utilizando una clase como resultado para decirle al mundo exterior que algo falló. Devuelve nulo o lanza una excepción cuando algo falla gravemente.

hth

Mario

+1

Devolver 'null' borra la información del error, y lanzar excepciones puede ser lento o molesto en algunas situaciones. Especialmente en programación funcional. – CodesInChaos

4

prefiero retirar IsSuccess y Message y devolver sólo el objeto. Vea a continuación ...

Eche un vistazo a mi pregunta Good practices when handling Exceptions in C#. Está devolviendo errores en lugar de arrojando excepciones, y en .NET, eso no es recomendable.

From MSDN:

No devolver códigos de error. Las excepciones son el principal medio para informar errores en los marcos.


Lo que está haciendo que se sugiere en algunos artículos/libros que he leído, incluyendo The Pragmatic Programmer: From Journeyman to Master y this Joel Spolsky article, pero según lo dicho por MSDN, en .NET excepciones son mejores para este propósito.

Editar:
Si aún desea hacerlo de ese modo (incluso si esa podría traer algunos problemas a los desarrolladores que están trabajando con su código), creo que, en general, que podría ser una Buen camino. De hecho, voy a editar la pregunta que vinculé en esta respuesta para colocar un enlace a su código para una alternativa de devolución de errores en lugar de arrojar Excepciones en .NET

+0

pero no quiero sólo manejos de excepción, quiero hacer mi fácil manejo validación, he editado mi pregunta, como a continuación si (tCategory.Name == null) { result.IsSuccess = false; result.Message = "Nombre de categoría no puede ser nulo"; result.Data = 0; } – tobias

+0

@tobias ¿Cuál es la diferencia entre eso y hacer: 'throw new ArgumentNullException (" Category Name no puede ser nulo ");' o simplemente 'throw new ArgumentNullException (" tCategory ");'? Quiero decir, todavía puedes validar y avisar a la persona que llamó cuál fue el error ... –

+0

No siempre es cierto, imagina que estás construyendo un Marco UI o un conjunto de algo que funciona dentro de una IU, si simplemente lanzas una excepción, IU predeterminada marco puede fallar al ejecutar sus propias tareas pendientes. ¿En qué otro lugar este patrón es realmente útil cuando no desea alterar el marco subyacente con sus excepciones y llevar a cabo sus tareas de una manera diferente? –

2

Si el alcance de su aplicación está completamente dentro del alcance de .NET, entonces este patrón no sirve de nada y, tal como otros lo han mencionado, debe dejar que se generen excepciones y es posible que desee cambiar las excepciones.

Sin embargo, si el alcance de su aplicación es amplio e incluye cualquier otro marco de trabajo del cliente, probablemente a través de JSON, servicios web, etc., y si el marco del cliente no admite excepciones, este patrón puede ser útil. Por ejemplo, en la llamada Javascript basada en JSON, siempre esperará un resultado y un mensaje que indique una falla en el servidor o no. La falla en el lado del cliente puede ser falla en el servidor o falla de red, generalmente todo el marco de trabajo del cliente detectará y solo reportará fallas de red y un marco incorrectamente codificado conducirá al caos cuando no reciba ningún informe de error del lado del cliente sobre qué falló exactamente lado del servidor.

un lugar más este patrón es muy útil es, cuando se escribe algunos plug-in en la interfaz de usuario o en el interior alguien marco de otra persona, donde sólo excepciones que lanzan pueden dar lugar a resultados no deseados como después de haber excepciones, marco terceros pueden decir "error inesperado "como no lo hacen y no están hechos para comprender tus excepciones". Este patrón es útil mientras se está dentro del marco de trabajo de otra persona y aún permite que el marco subyacente funcione correctamente independientemente de su falla. Y probablemente pueda comunicarse correctamente dentro del marco de su aplicación.

Recientemente he visto, y sigue siendo un error, WPF detiene el procesamiento de algunas actividades relacionadas con la interfaz de usuario si configura una fuente de una imagen que es una dirección web y que no existe. Verá una excepción relacionada con la red rastreada, pero WPF dejará de procesar de manera incompleta todo lo que estaba en tareas pendientes y la aplicación seguirá funcionando, pero sí afectará a otros elementos de la IU donde no debería.

+0

Un patrón similar es muy útil en la programación funcional. – CodesInChaos