在c#中访问泛型类的静态方法

时间:2009-09-01 03:04:40

标签: c# generics inheritance static methods

我在代码中遇到以下情况,我怀疑这可能有点过时了:

我有一个班级:

abstract class DataAccessBase<T> : IDataAccess where T : AnotherAbstractClass

此类DataAccessBase还有一个静态工厂方法,该方法使用哪个语句中的枚举值创建自身派生类的实例,以决定要创建哪个派生类型:

static IDataAccess CreateInstance(TypeToCreateEnum)

现在,从DataAccessBase<T>派生的类型本身并不是通用的,它们为T指定了一个类型:

class PoLcZoneData : DataAccessBase<PoLcZone> // PoLcZone is derived from AnotherAbstractClass

到目前为止,我不确定这是否会推动使用泛型的极限,但我真正关心的是如何首先访问静态CreateInstance()方法:

我现在这样做的方法是简单地传递任何类型T,其中T:AnotherAbstractClass。特别是我正在通过AnotherAbstractClass。这允许编译就好了,但在我看来,将任何类型传递给泛型类只是为了得到静态有点过时。

我实际上已经简化了这种情况,因为DataAccessBase<T>是继承链中的较低级别,但是静态工厂方法存在于中间层,其中PoLcZoneData等类派生的最多。只有非通用的等级。

人们对这种安排的看法是什么?

3 个答案:

答案 0 :(得分:10)

你可以拥有一个同名的非泛型类......也许是这样的:

abstract class DataAccessBase<T> : IDataAccess where T : AnotherAbstractClass
{
    ...
}
static class DataAccessBase
{
    public static IDataAccess CreateInstance(TypeToCreateEnum) {...}
}

现在,您可以使用DataAccessBase.CreateInstance而无需任何多余的T。通常情况下,您可以从internal调用DataAccessBase<T>上的DataAccessBase方法 - 虽然我怀疑在您的方案中您可能还需要一点反思/ MakeGenericType

答案 1 :(得分:2)

前段时间我遇到过类似的问题(“如何重载静态方法”),我用Reflection解决了这个问题。

这是我的情况:

1)public abstract class AuditObject<T> : ActiveRecordBase<T>(是的我正在使用ActiveRecord)和

2)public class Employee : AuditObject<Employee>

在两者中我都定义了一些静态方法,例如

public static DataTable GetLookupTable(String where, Int32 topRows)
{
    return doExtremelyCleverStuffToFetchData(where, topRows);
}

(在#2中你需要public **new** static或者你得到编译器警告)

代码是,当我打电话时,例如

DataTable myList = AuditObject<T>.GetLookupTable("inactive = 0", 100);

...并且T是Employee,静态方法不是“覆盖”,即执行的是(1)中的方法,而不是(2)。

所以在(1)中我修改了静态方法(在这个例子中,GetLookupTable),如下所示:

public static DataTable GetLookupTable(String where, Int32 topRows)
{
    DataTable tbl = null;

    Boolean hasOverride = hasMethodOverride("GetLookupTable");

    if (hasOverride)
    {
        tbl = invokeStaticMethod<T>(
            "GetLookupTable", new Object[2] { where, topRows })
            as DataTable;
    }
    else
    {
        tbl = doExtremelyCleverStuffToFetchData(where, topRows);
    }

    return tbl;
}

以下是我如何确定静态方法是否存在:

private static Boolean hasMethodOverride(String methodName)
{
    var methodQuery =
        from method in typeof(T).GetMethods(
            BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod)
        where method.Name == methodName
        select method;

    return methodQuery.Count() > 0;
}

以下是调用“覆盖”方法的方法:

public static Object invokeStaticMethod<T>(String MethodName, Object[] Args)
{
    return typeof(T).InvokeMember(MethodName,
        BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod,
        null, null, Args);
}
瞧!瞧!当我致电DataTable myList = AuditObject<T>.GetLookupTable("inactive = 0", 100);时 而T是Employee,我从Employee类中定义的静态方法得到结果。

希望这有帮助,

迪米瑞斯

答案 2 :(得分:0)

我认为该设计没有任何问题,特别是如果您使用模板参数指定实现细节。我建议的只是让工厂的功能不是静止的,而只是一个独立的。这对我来说是最明确的方式。

如果你想以某种方式封装它,我会建议命名空间或命名约定。

另一个解决方案就是隐藏你当前正在做的事情,通过定义一种类型的DataAccessBase可能是这样的:

typedef DataAccessBase<AnotherAbstractClass> DataAccessBaseFactory;

这是我最不推荐的解决方案,但是如果你绝对想要它,它会将Create函数保留为静态。