我在代码中遇到以下情况,我怀疑这可能有点过时了:
我有一个班级:
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
等类派生的最多。只有非通用的等级。
人们对这种安排的看法是什么?
答案 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函数保留为静态。