Generic <t>怎么演员?</t>

时间:2010-03-16 06:58:53

标签: c# generics casting ioc-container

我有一个“Product”基类,其他一些类“ProductBookDetail”,“ProductDVDDetail”继承自这个类。我使用ProductService类对这些类进行操作。但是,我必须根据类型(书的ISBN,DVD的语言)进行检查。我想知道投射“productDetail”值的最佳方法,我在SaveOrupdate中收到。我尝试使用GetType()并使用(ProductBookDetail)productDetail进行强制转换,但这不起作用。

谢谢,

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();
        }
    }
}

8 个答案:

答案 0 :(得分:3)

如果您需要了解该类型的字段或属性以便“保存或更新”,您可以使用反射。这样,该课程将保持真正的通用。

如果在SaveOrUpdate方法中,你的意思是编写一个相当于以下的不断扩展的开关:

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

然后你这样做是“错误的”。该类在其类型参数中并不是通用的。它仅适用于您指定的特定类型集。我在引号中说“错误”,因为在某些情况下它可能比可用的替代品更好,但这是不可取的。如果你有所有其他类型的后备,所以它总是有效,那么对某些类型的特殊情况可能是一种好的方法。

但是,您可以进行此类测试或投射。使用无约束类型参数T,您需要先将其转换为object

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

使用as关键字,您不需要额外转换为object

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

但更好的是,对于所有类型的产品详细信息类,如果存在公共基类ProductDetail,则将其用作T的约束:

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

我认为这样做是为了对类型参数使用更有意义的名称,例如TProductDetail,这是一种很好的做法。

如果你这样做,那么编译器应该让你“抛弃”从ProductDetail派生的东西,而不必先强制转换为object

答案 1 :(得分:3)

真是没有

如果你有非泛型属性(在通用接口契约中指定),那么你应该在SaveOrUpdate调用的接口中声明一个公共函数来处理这个

公共接口的每个实例(ProductDetailBook,productDetail等)将根据“//我不知道类型和访问属性取决于类”的要求以不同方式定义此函数。

你正在拉类特定代码并将其放入一个通用函数,这是意大利面条代码的开始

这是没有通用服务的众多原因之一

答案 2 :(得分:3)

我并不是说要批评,但这种模式对我来说感觉不好。

我听说过其他人说如果你采用通用方法的类型,那么你最有可能做错了。

我将通过声明一个基类方法来帮助重构 SaveOrUpdate 方法来重构代码,然后让派生类覆盖该方法。现在,当您在泛型方法中调用基类方法时,您将获得派生类implmentation

答案 3 :(得分:0)

如果我理解你的问题,你试图从一个返回基类的函数中确定你的派生类。您需要使用IS运算符

您可以看到如何使用下面的运算符。

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;
       }
   }


}

}

答案 4 :(得分:0)

在泛型方法中,您必须使用as关键字进行转换才能执行此类转换。有很好的理由,但它的故事很长......

如果您对仿制药做了很多工作,请阅读Bill Wagners的“更有效的C#”,以便更清楚地处理这个问题。

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

答案 5 :(得分:0)

也许您应该按如下方式重构代码:

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
       }
    }
}

此代码更适合OOP。它更简单,更具可扩展性,更不容易出错。

P.S。不要忘记S.O.L.I.D.

答案 6 :(得分:0)

我会查找Strategy pattern并将其与您的通用存储库结合使用。然后,您可以在实体的某个界面中定义策略,这会强制它们实现某些方法,如CheckConstraints。在通用存储库中,然后在执行CheckConstraints之前调用SaveOrUpdate

答案 7 :(得分:-2)

使用:

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

和其他人一样。