2009-09-01 3 views
4

У меня есть следующая ситуация в коде, который я подозреваю, может быть немного dodgey:Доступ к статическим методам на Generic класса в C#

У меня есть класс:

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

Этот класс DataAccessBase также имеет статический метод завода, который создает экземпляры производных классов само по себе, используя значение перечисления в каком заявлении решить, какой производный тип создания:

static IDataAccess CreateInstance(TypeToCreateEnum) 

Теперь Ty ПЭС, полученные из DataAccessBase<T> сами не являются универсальными, они определяют тип для T:

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

До сих пор я не уверен, если это раздвигает границы эффективного использования дженериков, но то, что я на самом деле беспокоит то, как для доступа к статическому методу CreateInstance():

То, как я делаю это на данный момент, - это просто передать любой тип T, где T: AnotherAbstractClass. В частности, я прохожу AnotherAbstractClass. Это позволяет компиляции просто отлично, но мне кажется, что передача какого-либо типа в общий класс просто для того, чтобы попасть на статику, немного запутанна.

Я на самом деле упрощена ситуация несколько, как DataAccessBase<T> это нижний уровень в цепочке наследования, но статические методы завод существует в среднем ряду с классами, такими, как PoLcZoneData причем наиболее полученных на единственном уровне, который не является универсальным.

Что представляют собой мысли людей о таком расположении?

+0

Какого языку это? –

+0

Извините, его C#. Забыл добавить это в заголовок. – MrLane

ответ

9

Вам разрешено иметь не универсальный класс с таким же названием ... возможно, что-то вроде:

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

Теперь вы можете использовать DataAccessBase.CreateInstance без избыточного T. Как правило, вы можете называть internal методами на DataAccessBase<T> от DataAccessBase - хотя я подозреваю, что в вашем сценарии вам может понадобиться небольшое отражение/MakeGenericType.

0

Я не думаю, что с этим дизайном что-то не так, особенно если вы используете параметр шаблона, чтобы указать деталь реализации. То, что я хотел бы предложить, было бы просто заставить фабричную функцию не быть статичной, а просто самостоятельной. Это было бы самым понятным способом для меня.

Если вы хотите каким-то образом инкапсулировать его, я бы предложил пространство имен или соглашение об именах.

Еще одно решение было бы просто скрывать то, что вы сейчас делаете, определив тип DataAccessBase, может быть, например, так:

typedef DataAccessBase<AnotherAbstractClass> DataAccessBaseFactory; 

Это мое наименьшее рекомендуемое решение, но оно оставляет функцию Create как статические если вы этого абсолютно хотите.

+0

@killerfox Это C# –

+0

Хорошо, в этом случае я предполагаю, что единственным вариантом является инкапсуляция фабричной функции в отдельный класс вместо пространства имен –

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

... и Т Сотрудник, статический метод не является «переопределенным» то есть тот, который выполняется метод в (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); 
} 

Voila! Когда я вызываю DataTable myList = AuditObject<T>.GetLookupTable("inactive = 0", 100); и T является Employee, я получаю результаты статического метода, определенного в классе Employee.

Надеется, что это помогает,

Димитрис

Смежные вопросы