C# 通用<;T>;怎么投?

C# 通用<;T>;怎么投?,c#,generics,casting,ioc-container,C#,Generics,Casting,Ioc Container,我有一个“Product”基类,其他一些类“ProductBookDetail”、“ProductDVD Detail”继承自这个类。我使用ProductService类对这些类进行操作。但是,我必须根据类型做一些检查(图书的ISBN,DVD的语言)。我想知道在SaveOrupdate中获得“productDetail”值的最佳方式。我尝试了GetType()并使用(ProductBookDetail)productDetail进行强制转换,但这不起作用 谢谢 var productDetail

我有一个“Product”基类,其他一些类“ProductBookDetail”、“ProductDVD Detail”继承自这个类。我使用ProductService类对这些类进行操作。但是,我必须根据类型做一些检查(图书的ISBN,DVD的语言)。我想知道在SaveOrupdate中获得“productDetail”值的最佳方式。我尝试了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();
        }
    }
}
var-productDetail=new-ProductDetailBook(){….};
var service=IoC.Resolve();
服务。保存或更新(productDetail);
var productDetail=new ProductDetailDVD(){….};
var service=IoC.Resolve();
服务。保存或更新(productDetail);
公共类ProductServiceGeneric:IPProductServiceGeneric
{
专用只读会话;
私有只读IPProductRepoGeneric \u repo;
公共产品服务通用()
{
_会话=UnitOfWork.CurrentSession;
_repo=IoC.Resolve();
}
公共作废保存或更新(T productDetail)
{            
使用(ITransaction tx=\u session.BeginTransaction())
{
//在这里,我想知道的类型和访问属性取决于类
_回购、保存或更新(产品详情);
tx.Commit();
}
}
}
使用:


其他人也是如此。

如果我理解你的问题,你是在试图确定你从一个返回基类的函数中得到了什么样的派生类。您需要使用
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;
       }
   }


}

}

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

如果在
SaveOrUpdate
方法中,您打算编写一个不断扩展的开关,相当于:

if (it's type A) { deal with type A }
else if (it's type B) { deal with type B }
... and so on
那你就“做错了”。该类的类型参数不是真正的泛型。它仅适用于指定的特定类型集。我用引号说“错”,因为在某些情况下,它可能比可用的替代方案更好,但这是不可取的。如果您对所有其他类型都有回退,因此它总是有效的,那么对于某些类型来说,使用特殊情况可能是一种不错的方式

然而,你可以做这样的测试,或铸造。对于无约束类型参数,
T
,您需要首先将其强制转换为
对象

var eitherStringOrNull = (string)((object)somethingOfTypeT);
使用
as
关键字,您不需要对
对象进行额外转换

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
公共类ProductServiceGeneric:IPProductServiceGeneric
其中T:ProductDetail
我认为这样做时最好使用更有意义的类型参数名称,例如
TProductDetail

如果您这样做,那么编译器应该允许您“向下转换”到从
ProductDetail
派生的内容,而不必首先转换到
对象

如果您具有非泛型属性(如公共接口契约中指定的),那么您应该在接口中声明一个公共函数,该函数由SaveOrUpdate调用以处理此问题

公共接口的每个实例(ProductDetailBook、productDetail等)都将根据“/”的要求对该函数进行不同的定义。在这里,我想知道类型和访问属性,具体取决于类”

您正在提取特定于类的代码并将其放入一个公共函数中,这是意大利面代码的开始


这是不提供通用服务的众多原因之一,我并不想批评,但这种模式让我感觉很糟糕

我听其他人说,如果你在泛型方法中使用类型,那么你很可能做错了什么


我将通过声明一个基类方法来重构代码,以帮助使用SaveOrUpdate方法,然后让派生类重写该方法。现在,当您在泛型方法中调用基类方法时,您将在泛型方法中得到派生类的实现,您必须使用
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(); 
    } 
} 

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

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
       }
    }
}
抽象类产品
{
公共抽象bool CheckProduct();
}
类别ProductBookDetail:产品
{
公共覆盖布尔检查产品()
{
//在这里我们可以查看ProductBookDetail
}
}
类别ProductDetailDVD:产品
{
公共覆盖布尔检查产品()
{
//在这里我们可以查看ProductDetailDVD
}
}
公共类ProductServiceGeneric:IPProductServiceGeneric,其中T:ProductDetail
{
公共作废保存或更新(T产品)
{
如果(!product.CheckProduct())
{
//产品检查失败。请在此添加必要的逻辑
}
}
}
这段代码更适合OOP。它更简单,更具可扩展性,更不容易出错


注意:别忘了

我会查找,也许会将其与您的通用存储库结合使用。然后,您可以在一些界面中为实体定义策略,这迫使它们实现一些方法,如
CheckConstraints
。然后在通用存储库中调用
CheckConstraints
,然后再执行
SaveOrUpdate

如果您不需要保存任何不同的数据,也许您应该创建一个具体的服务,并将保存或更新保留为通用的,或者您可以在orm中使用继承。对哪个具体实体的需求听起来很奇怪:通常您会执行如下操作:new ProductServiceGeneric()。所有代码都将是一本书
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
       }
    }
}