2010-03-16 101 views
6

我有一个“Product”基类,其他一些类“ProductBookDetail”,“ProductDVDDetail”继承自这个类。我使用ProductService类来对这些类进行操作。但是,我必须根据类型进行一些检查(书籍的ISBN,DVD的语言)。我想知道投放“productDetail”值的最佳方式,我在SaveOrupdate中收到。我试过的GetType()和投用(ProductBookDetail)productDetail但是这不行通用<T>如何投射?

感谢,

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

也许你应该做一个具体的服务,留下的保存或更新通用的,如果你不需要保存任何不同的数据,或者你可以在你的ORM使用继承。其中需要具体实体听起来很奇怪:通常你做这样的事情: 新ProductServiceGeneric ()。而且你的代码中的所有内容都是书籍,所以你不必知道。 –

回答

-2

用途:。

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

,类似的还有其他

+0

为什么选择投票? – logicnp

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


} 

}

+0

是在合适的班级 –

+0

了'as'运营商在这种情况下更好的投(和检查空之后) –

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

+0

Downvoter - 怎么样的评论? –

3

真是没有

如果有非一般属性(如通用接口合同规定),那么你应该在接口声明的公共功能由SaveOrUpdate调用来处理这个

的每个实例常见的界面(ProductDetailBook,productDetail等)将根据“//这里我不知道取决于类的类型和访问属性”所需的不同来定义该函数“

您正在拉类专用代码并将其放入一个共同的功能,这是意大利面条的开始代码

这是众多原因之一,不具有通用服务

3

我的意思并不是很重要,但这种模式只是感觉对我不好。

我听到别人说如果你采用泛型方法的类型,那么你很可能做错了什么。

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

0

在泛型方法中,您必须使用as关键字进行强制类型转换。有充分的理由,但它的一个漫长的故事...

如果你做了很多泛型,读比尔瓦格纳“更有效的C#”的替代方法,以这种更清洁处理。

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更合适:

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

也许你如下应该重构你的代码。它简单得多,扩展性更强,而且更容易出错。

P.S.不要忘了S.O.L.I.D.

0

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