我有一个“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();
}
}
}
答案 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)
{
...
...
}
和其他人一样。