如何通过基类中的方法返回Generic Type?

时间:2009-03-02 19:18:51

标签: c# .net design-patterns generics activerecord

我一直在尝试创建一个简单的基类,它封装了我的一些数据库访问约定。我通常会创建一个名为“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;
    }
}

4 个答案:

答案 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,可能是扩展方法)。