[英]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.