2010-03-16 16 views
6

Tengo una clase base de "Producto", algunas otras clases "ProductBookDetail", "ProductDVDDetail" heredan de esta clase. Utilizo una clase ProductService para hacer operación en estas clases. Pero, tengo que hacer un control dependiendo del tipo (ISBN para Libro, idiomas para DVD). Me gustaría saber la mejor manera de emitir el valor "productDetail", que recibo en SaveOrupdate. Probé GetType() y fundido con (ProductBookDetail)productDetail pero eso no es trabajo<T> genérico ¿cómo emitir?

Gracias,

var productDetail = new ProductDetailBook() { .... }; 
var service = IoC.Resolve<IProductServiceGeneric<ProductDetailBook>>(); 
service.SaveOrUpdate(productDetail); 

var productDetail = new ProductDetailDVD() { .... }; 
var service = IoC.Resolve<IProductServiceGeneric<ProductDetailDVD>>(); 
service.SaveOrUpdate(productDetail); 


public class ProductServiceGeneric<T> : IProductServiceGeneric<T> 
{ 
    private readonly ISession _session; 
    private readonly IProductRepoGeneric<T> _repo; 
    public ProductServiceGeneric() 
    { 
     _session = UnitOfWork.CurrentSession; 
     _repo = IoC.Resolve<IProductRepoGeneric<T>>(); 
    } 
    public void SaveOrUpdate(T productDetail) 
    {    
     using (ITransaction tx = _session.BeginTransaction()) 
     { 
      //here i'd like ot know the type and access properties depending of the class 
      _repo.SaveOrUpdate(productDetail); 
      tx.Commit(); 
     } 
    } 
} 
+0

tal vez deba hacer un servicio concreto y dejar guardado o actualizar genérico si no necesita guardar datos diferentes, o puede usar la herencia en su orm. La necesidad de que la entidad concreta suene extraña: normalmente haces algo como: new ProductServiceGeneric (). Y todo en tu código será libros, por lo que no tienes que saberlo. –

Respuesta

-2

Uso:..

if(productDetail is ProductDetailBook) 
{ 
... 
... 
} 

y lo mismo para los demás

+0

¿Por qué votar abajo? – logicnp

0

si entiendo su pregunta si está intentando determinar qué clase derivada tiene de una función que devuelve una clase base. Debe utilizar el operador IS

puede ver cómo utilizar el operador a continuación.

class Base 
{ 
} 

class AB : Base 
{ 

} 
class AC : Base { } 

class Program 
{ 
    static Base GetObject() 
    { 
     return null; 
    } 
    static void Main(string[] args) 
    { 
     Base B = GetObject(); 
     if (B is AB) 
     { 
      AB DevClass =(AB) B; 
     } 
    } 


} 

}

+0

Sí y lanzar en la clase correcta –

+0

el operador 'as' es mejor en este caso (y luego buscar nulo) –

3

Si lo que necesita saber acerca de los campos o propiedades del tipo con el fin de "salvar o actualización", se podría utilizar la reflexión. De esa forma, la clase permanecería verdaderamente genérica.

Si dentro de su método de SaveOrUpdate que significas para escribir un interruptor en constante expansión equivalente a:

if (it's type A) { deal with type A } 
else if (it's type B) { deal with type B } 
... and so on 

Entonces lo estás haciendo "mal". Esa clase no es realmente genérica en su parámetro de tipo. Solo funciona con el conjunto específico de tipos que especificó. Digo "incorrecto" entre comillas porque podría ser mejor que las alternativas disponibles en algunas situaciones, pero no es deseable. Si tiene un repliegue para todos los demás tipos, por lo que siempre funciona, entonces podría ser una buena manera de tener casos especiales para ciertos tipos.

Sin embargo, usted puede hacer una prueba o casting. Con un parámetro de tipo de restricciones, T, es necesario echarlo a object primera:

var eitherStringOrNull = (string)((object)somethingOfTypeT); 

con la palabra clave as que no es necesario que el molde extra para object.

var eitherStringOrNull = somethingOfTypeT as string; 
if (eitherStringOrNull != null) 
{ 
    .. it was a string, so we can use it as such 
} 

Pero aún mejor, si hay una clase base común, ProductDetail, para todo tipo de clase de detalles del producto, y luego usar eso como una restricción en T:

public class ProductServiceGeneric<T> : IProductServiceGeneric<T> 
     where T : ProductDetail 

Creo que es una buena práctica al hacer eso para usar un nombre más significativo para el parámetro de tipo, como TProductDetail.

Si hace esto, entonces el compilador debería permitirle "arrojarlo" a algo derivado de ProductDetail, sin tener que convertirlo primero al object.

+0

Downvoter: ¿qué tal un comentario? –

3

Nooooo

Si tiene propiedades no genéricos (como se especifica en el contrato de interfaz común), entonces usted debe tener una función común declarado en la interfaz que se llama por saveOrUpdate para manejar este

Cada instancia de la La interfaz común (ProductDetailBook, productDetail, etc.) definirá esta función de forma diferente según lo requiera "// aquí me gustaría saber el tipo y las propiedades de acceso de la clase"

Está sacando el código específico de la clase y colocándolo en una función común, este es el comienzo de los espaguetis código

Ésta es una de las muchas razones para no tener servicios genéricos

3

no me refiero a ser crítico, pero ese patrón simplemente siente mal a mí.

He escuchado a otros decir que si está tomando un tipo en un método genérico, entonces lo más probable es que esté haciendo algo mal.

Me refactorizar su código declarando un método de la clase base para ayudar con el método saveOrUpdate, luego hacer que las clases derivadas de anulación ese método. Ahora cuando llame al método de clase base en el método genérico, obtendrá la implementación de las clases derivadas

0

Dentro de los métodos genéricos, debe usar el as palabra clave para hacer moldes como este. Hay buenas razones por las cuales es una historia larga ...

Si haces mucho con los genéricos, lee Bill Wagners "Más efectivo C#" para encontrar maneras alternativas de lidiar con esto más limpiamente.

public void SaveOrUpdate(T productDetail) 
{    
    using (ITransaction tx = _session.BeginTransaction()) 
    { 
     ProductDetailBook bookDetail = productDetail as ProductDetailBook; 
     if (bookDetail != null) 
      _repo.SaveOrUpdate(bookDetail); 
     tx.Commit(); 
    } 
} 
0

Tal vez deberías refactorizar el código de la siguiente manera:

abstract class Product 
{ 
    public abstract bool CheckProduct(); 
} 
class ProductBookDetail : Product 
{ 
    public override bool CheckProduct() 
    { 
     //Here we can check ProductBookDetail 
    } 
} 

class ProductDetailDVD : Product 
{ 
    public override bool CheckProduct() 
    { 
     //Here we can check ProductDetailDVD 
    } 
} 

public class ProductServiceGeneric<T> : IProductServiceGeneric<T> where T : ProductDetail 
{ 
    public void SaveOrUpdate(T product) 
    { 
     if (!product.CheckProduct()) 
     { 
      //product checking failes. Add necessary logic here 
     } 
    } 
} 

Este código es mucho más apropiado para la programación orientada a objetos. Es mucho más simple, es más extensible y menos propenso a errores.

P.S. No se olvide de S.O.L.I.D.

0

Me gustaría buscar Strategy pattern y tal vez usar eso en conjunto con su repositorio genérico. Luego puede definir su estrategia en alguna interfaz para sus entidades, lo que les obliga a implementar algún método como CheckConstraints. En su repositorio genérico, llame al CheckConstraints antes de ejecutar SaveOrUpdate.

Cuestiones relacionadas