我一直在尝试创建一个简单的基类,它封装了我的一些数据库访问约定。我通常会创建一个名为“products_retrieve_product”的sproc来根据productID选择产品。我希望基类中的方法“Retrieve”返回派生类在其定义中提供的类型。我想通过泛型来实现这个目标吗?
public class MyBaseClass <T>
{
private string _className;
public MyBaseClass ()
{
_className = this.GetType().Name;
}
public virtual T Retrieve(int ID)
{
Database db = DatabaseFactory.CreateDatabase();
DbCommand dbCommand = db.GetStoredProcCommand(String.Format("{0}s_Retrieve_{0}", _className));
db.AddInParameter(dbCommand, String.Format("@{0}ID", _className), DbType.Int32, ID);
using (IDataReader dr = db.ExecuteReader(dbCommand))
{
if (dr.Read())
{
BOLoader.LoadDataToProps(this, dr);
}
}
return (T)this;
}
}
答案 0 :(得分:2)
我认为你想做这样的事情:
class MyBaseClass<T> where T : MyBaseClass<T>, new()
{
public T Retrieve()
{
return new T();
}
}
class Foo : MyBaseClass<Foo>
{
}
class Program
{
public static void Main()
{
Foo f = new Foo();
Foo f2 = f.Retrieve();
Console.WriteLine(f2.ToString());
}
}
运行此程序时,命令行上会打印Foo的类型名称。显然这是一个人为的例子,但是从MyBaseClass.Retrieve()
中的数据库加载时,你可以做一些更有用的事情。
关键是在T上添加一个约束,使它必须是类本身的一个实例。这样,您可以在子类化MyBaseClass<T>.
我不完全确定这是不是一个好主意,但看起来可以做到。
答案 1 :(得分:1)
不确定。在您的示例中,如果我希望我的Foo类在调用Retrieve(...)时返回Bars:
public class Foo : MyBaseClass<Bar>{}
答案 2 :(得分:0)
嗯,我们使用反射来获取类名。毫无疑问,BOLoader使用反射来加载一些属性。为什么不完全承诺反思?
BOLoader并不关心这种“回归类型”游戏。我们为什么要这样做?
public static class MyBaseClassExtender
{
public static void Retrieve(this MyBaseClass entity, int ID)
{
string className = entity.GetType().Name;
Database db = DatabaseFactory.CreateDatabase();
DbCommand dbCommand = db.GetStoredProcCommand(String.Format("{0}s_Retrieve_{0}", className));
db.AddInParameter(dbCommand, String.Format("@{0}ID", className), DbType.Int32, ID);
using (IDataReader dr = db.ExecuteReader(dbCommand))
{
if (dr.Read())
{
BOLoader.LoadDataToProps(this, dr);
}
}
}
}
然后你就说:
Foo myFoo = new Foo();
myFoo.Retrieve(2);
答案 3 :(得分:-1)
不,不是,因为你真正需要做的就是在类定义中这样做:
public class MyBaseClass<T> : T
目前无法使用泛型。
您需要做的是将工厂与工厂生产的工厂分开(您需要一个单独的类来构建T,然后您应该提供辅助方法来处理T,可能是扩展方法)。