【问题标题】:Accessing Static Methods on a Generic class in c#在 C# 中访问泛型类的静态方法
【发布时间】:2010-11-24 12:35:06
【问题描述】:

我在代码中有以下情况,我怀疑可能有点躲闪:

我有一堂课:

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

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

static IDataAccess CreateInstance(TypeToCreateEnum)

现在,从DataAccessBase&lt;T&gt; 派生的类型本身不是通用的,它们为 T 指定了一个类型:

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

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

我目前这样做的方式是简单地传递任何类型 T 其中 T :AnotherAbstractClass。特别是我通过AnotherAbstractClass 本身。这允许编译很好,但在我看来,将任何类型传递给泛型类只是为了获得静态数据有点狡猾。

实际上,我已经稍微简化了这种情况,因为DataAccessBase&lt;T&gt; 是继承链中的较低级别,但静态工厂方法存在于中间层,其中 PoLcZoneData 等类是在唯一级别上派生最多的,即不是通用的。

人们对这种安排有何看法?

【问题讨论】:

  • 对不起,它是 C#。忘记在标题中添加了。

标签: c# generics inheritance static methods


【解决方案1】:

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

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

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

typedef DataAccessBase<AnotherAbstractClass> DataAccessBaseFactory;

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

【讨论】:

  • 好的,在这种情况下,我想唯一的选择是将工厂函数封装在单独的类中而不是命名空间中
【解决方案2】:

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

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

现在您可以使用DataAccessBase.CreateInstance,而无需任何多余的T。通常,您可能会从 DataAccessBase 调用 DataAccessBase&lt;T&gt; 上的 internal 方法 - 尽管我怀疑在您的场景中您可能还需要一点反思 / MakeGenericType

【讨论】:

    【解决方案3】:

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

    这是我的情况:

    1) public abstract class AuditObject&lt;T&gt; : ActiveRecordBase&lt;T&gt;(是的,我正在使用 ActiveRecord)和

    2) public class Employee : AuditObject&lt;Employee&gt;

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

    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&lt;T&gt;.GetLookupTable("inactive = 0", 100); 而 T 是 Employee,我从 Employee 类中定义的静态方法得到结果。

    希望这会有所帮助,

    迪米特里斯

    【讨论】:

      猜你喜欢
      • 2011-08-19
      • 2012-02-27
      • 2020-05-07
      • 1970-01-01
      • 2014-07-06
      • 2012-02-10
      • 2010-10-30
      • 2010-10-16
      相关资源
      最近更新 更多