简体   繁体   English

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

[英]Accessing Static Methods on a Generic class in c#

I have the following situation in code, which I suspect may be a bit dodgey: 我在代码中有以下情况,我怀疑这可能有点过于谨慎:

I have a class: 我有一节课:

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

This class DataAccessBase also has a static factory method which creates instances of derived classes of itself using an enum value in a which statement to decide which derived type to create: 此类DataAccessBase还有一个静态工厂方法,该方法使用where语句中的枚举值创建自身派生类的实例,以决定要创建的派生类型:

static IDataAccess CreateInstance(TypeToCreateEnum)

Now, the types derived from DataAccessBase<T> are themselves NOT generic, they specify a type for T: 现在,从DataAccessBase<T>派生的类型本身不是通用的,它们为T指定了一个类型:

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

So far I am not sure if this is pushing the limits of good use of generics, but what I am really concerned about is how to access the static CreateInstance() method in the first place: 到目前为止,我不确定这是否正在推动使用泛型的极限,但我真正关心的是如何首先访问静态CreateInstance()方法:

The way I am doing this at the moment is to simply pass any type T where T : AnotherAbstractClass . 我现在这样做的方法是简单地传递任何类型T T: AnotherAbstractClass In particular I am passing AnotherAbstractClass itself. 特别是我正在传递AnotherAbstractClass本身。 This allows compilation just fine, but it does seem to me that passing any type to a generic class just to get at the statics is a bit dodgey. 这允许编译很好,但在我看来,将任何类型传递给泛型类只是为了得到静态有点过于愚蠢。

I have actually simplified the situation somewhat as DataAccessBase<T> is the lower level in the inheritance chain, but the static factory methods exists in a middle tier with classes such as PoLcZoneData being the most derived on the only level that is not generic. 我实际上已经简化了这种情况,因为DataAccessBase<T>是继承链中的较低级别,但静态工厂方法存在于中间层,其中诸如PoLcZoneData类的类是在非泛型的唯一级别上派生得最多的。

What are peoples thoughts on this arrangement? 人们对这种安排的看法是什么?

You are allowed to have a non-generic class of the same name... perhaps something like: 你可以拥有一个同名的非泛型类......也许是这样的:

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

Now you can use DataAccessBase.CreateInstance without any redundant T . 现在您可以使用DataAccessBase.CreateInstance而无需任何冗余T Typically, you might call internal methods on DataAccessBase<T> from DataAccessBase - although I suspect in your scenario you might also need a little reflection / MakeGenericType . 通常,您可以从DataAccessBase调用DataAccessBase<T>上的internal方法 - 尽管我怀疑在您的场景中您可能还需要一点反射/ MakeGenericType

I've ran into a similar problem a while ago ("how to overload static methods") and I solved it with Reflection. 我刚才遇到了类似的问题(“如何重载静态方法”),我用Reflection解决了它。

Here's my situation : 这是我的情况:

1) public abstract class AuditObject<T> : ActiveRecordBase<T> (yes I'm using ActiveRecord) and 1) public abstract class AuditObject<T> : ActiveRecordBase<T> (是的,我正在使用ActiveRecord)和

2) public class Employee : AuditObject<Employee> 2) public class Employee : AuditObject<Employee>

In both of them I define some static Methods, eg 在这两个中我定义了一些静态方法,例如

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

(in #2 you need public **new** static or else you get a compiler warning) (在#2中你需要public **new** static或者你得到编译器警告)

As the code is, when I call eg 当代码是,当我打电话时,例如

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

...and T is Employee, the static method is not "overriden" ie the one that is executed is the method in (1), not (2). ...而T是Employee,静态方法不是“覆盖”,即执行的是(1)中的方法,而不是(2)。

So in (1) I modified the static methods (in this example, GetLookupTable) like this : 所以在(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;
}

Here's how I find out if the static method exists : 以下是我如何确定静态方法是否存在的方法:

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;
}

And here's how the "override" method is called : 以下是调用“覆盖”方法的方法:

public static Object invokeStaticMethod<T>(String MethodName, Object[] Args)
{
    return typeof(T).InvokeMember(MethodName,
        BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod,
        null, null, Args);
}

Voila ! 瞧! When I call DataTable myList = AuditObject<T>.GetLookupTable("inactive = 0", 100); 当我调用DataTable myList = AuditObject<T>.GetLookupTable("inactive = 0", 100); and T is Employee, I get results from the static method defined in the Employee class. 而T是Employee,我从Employee类中定义的静态方法得到结果。

Hope this helps, 希望这可以帮助,

Dimitris 季米特里斯

I don't think there is anything wrong with that design, specially if you are using the template parameter to specify an implementation detail. 我不认为该设计有任何问题,特别是如果您使用模板参数指定实现细节。 What I would suggest would be simply to have the factory function not be static, but just a stand alone. 我建议的只是让工厂的功能不是静止的,而只是一个独立的。 That would be the most clearcut way to go about it for me. 这对我来说是最明确的方式。

If you want to encapsulate it in some way I would then suggest a namespace, or a naming convention. 如果你想以某种方式封装它,我会建议命名空间或命名约定。

Yet another solution would be just hiding what you are currently doing, by defining a type of DataAccessBase maybe like so: 另一个解决方案是隐藏你当前正在做的事情,通过定义一种类型的DataAccessBase可能是这样的:

typedef DataAccessBase<AnotherAbstractClass> DataAccessBaseFactory;

This is my least recommended solution, but it leaves the Create function as a static if you absolutely want it to be. 这是我最不推荐的解决方案,但如果你绝对想要它,它会将Create函数保留为静态。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM