2008-08-18 4 views
10

Во-первых, я понимаю причины, по которым интерфейс или абстрактный класс (в терминологии .NET/C#) не могут иметь абстрактные статические методы. Мой вопрос тогда больше сфокусирован на лучшем дизайнерском решении.Статические методы в интерфейсе/абстрактном классе

Что я хочу - это набор «вспомогательных» классов, для которых все имеют свои собственные статические методы, так что если я получаю объекты A, B и C от стороннего поставщика, у меня могут быть вспомогательные классы с такими методами, как

 
AHelper.RetrieveByID(string id); 
AHelper.RetrieveByName(string name); 
AHelper.DumpToDatabase(); 

Поскольку мои классы AHelper, BHelper и CHelper будут в основном иметь одни и те же методы, кажется, имеет смысл перемещать эти методы в интерфейс, из которого эти классы берутся. Однако, если эти методы являются статическими, это не позволяет мне получить общий интерфейс или абстрактный класс для всех из них.

Я всегда мог сделать эти методы не статическую, а затем создавать экземпляры объектов, таких как первые

 
AHelper a = new AHelper(); 
a.DumpToDatabase(); 

Однако этот код не кажется, как интуитивно мне. Каковы ваши предложения? Должен ли я отказаться от использования интерфейса или абстрактного класса в целом (ситуация, в которой я сейчас сейчас), или это может быть реорганизовано для выполнения проекта, который я ищу?

ответ

3

Looking на your response Я думаю следующие строки:

  • У вас может быть только статический метод, который принимает параметр типа и выполняет ожидаемую логику, основанную на типе.
  • Вы можете создать виртуальный метод в своей абстрактной базе, где вы укажете SQL в конкретном классе. Таким образом, он содержит весь общий код, который требуется обоими (например, вытеснение команды и возвращение объекта) при инкапсуляции «специализированных» битов (например, SQL) в подклассы.

Я предпочитаю второй вариант, хотя он, конечно, относится к вам. Если вам нужно, чтобы я вдаваться в дальнейшие подробности, пожалуйста, дайте мне знать, и я буду счастлив редактировать/обновить :)

+0

IMHO: Первый вариант был бы лучше, чем общий, поэтому можно использовать вывод типа, который еще лучше. – 2011-07-14 10:08:09

1

В C# 3.0, статические методы могут быть использованы на интерфейсах, как если бы они были частью их с помощью методов расширения, как и с DumpToDatabase() ниже:

static class HelperMethods 
{ //IHelper h = new HeleperA(); 
    //h.DumpToDatabase() 
    public static void DumpToDatabase(this IHelper helper) { /* ... */ } 

    //IHelper h = a.RetrieveByID(5) 
    public static IHelper RetrieveByID(this ObjectA a, int id) 
    { 
      return new HelperA(a.GetByID(id)); 
    } 

    //Ihelper h = b.RetrieveByID(5)  
    public static IHelper RetrieveByID(this ObjectB b, int id) 
    { 
      return new HelperB(b.GetById(id.ToString())); 
    } 
} 
2

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

Почему бы не создать класс utlity со статическими методами, которые им необходимо разделить? (Например, ClassHelper.RetrieveByID(string id) или ClassHelper<ClassA>.RetrieveByID(string id)

В моем опыте этих родов «блокпосты» проблема заключается не ограничения языка, но ограничения моей конструкции ..

2

Как Objecta и AHelper связаны? Является ли AHelper.RetrieveByID() тот же логик, как BHelper.RetrieveByID()

Если да, то как насчет подхода, основанного на Полезность класса (класс только с публичными статическими методами и не в том состоянии)

static [return type] Helper.RetrieveByID(ObjectX x) 
0

как d o Я отправляю отзыв о переполнении стека? Редактировать мой оригинальный пост или отправить ответ? Во всяком случае, я подумал, что это может помочь привести пример того, что происходит в AHelper.RetrieveByID() и BHelper.RetreiveByID()

В принципе, оба этих метода подходят к стороннему веб-сервису, который возвращает различные общий (castable) объект с использованием метода Query, который принимает строку псевдо-SQL как свои единственные параметры.

Так, AHelper.RetrieveByID (строка ID) может выглядеть

 
public static AObject RetrieveByID(string ID) 
{ 
    QueryResult qr = webservice.query("SELECT Id,Name FROM AObject WHERE Id = '" + ID + "'"); 

    return (AObject)qr.records[0]; 
} 

public static BObject RetrieveByID(string ID) 
{ 
    QueryResult qr = webservice.query("SELECT Id,Name,Company FROM BObject WHERE Id = '" + ID + "'"); 

    return (BObject)qr.records[0]; 
} 

Хотелось бы надеяться, что помогает. Как вы можете видеть, эти два метода похожи, но запрос может быть немного иным, в зависимости от возвращаемого типа объекта.

О, и Роб, я полностью согласен - это более чем вероятно ограничение моего дизайна, а не языка.:)

0

Вы ищете полиморфное поведение? Тогда вам понадобится интерфейс и обычный конструктор. Что неинтересно в вызове конструктора? Если вам не нужен полиморфизм (кажется, что вы его не используете сейчас), вы можете придерживаться своих статических методов. Если это все обертки вокруг компонента поставщика, возможно, вы попытаетесь использовать фабричный метод для их создания, например VendorBuilder.GetVendorThing («A»), который может вернуть объект типа IVendorWrapper.

2

Вы не можете перегружать методы, изменяя только тип возврата.

Вы можете использовать различные имена:

static AObject GetAObject(string id); 
static BObject GetBObject(string id); 

Или вы можете создать класс с операторами литья:

class AOrBObject 
{ 
    string id; 
    AOrBObject(string id) {this.id = id;} 

    static public AOrBObject RetrieveByID(string id) 
    { 
     return new AOrBObject(id); 
    } 

    public static AObject explicit operator(AOrBObject ab) 
    { 
     return AObjectQuery(ab.id); 
    } 

    public static BObject explicit operator(AOrBObject ab) 
    { 
     return BObjectQuery(ab.id); 
    } 
} 

Тогда вы можете назвать это как так:

var a = (AObject) AOrBObject.RetrieveByID(5); 
var b = (BObject) AOrBObject.RetrieveByID(5); 
3

Для общего решения вашего примера, вы можете сделать это:

public static T RetrieveByID<T>(string ID) 
{ 
    var fieldNames = getFieldNamesBasedOnType(typeof(T)); 
    QueryResult qr = webservice.query("SELECT "+fieldNames + " FROM " 
            + tyepof(T).Name 
            +" WHERE Id = '" + ID + "'"); 
    return (T) qr.records[0]; 
} 
+0

+1.Я делаю это в нескольких запросах libs, особенно те, которые проходят через веб-службы. – jro 2009-09-24 22:45:29

5

Если Я был вами, я постараюсь избежать статики. ИМХО. Я всегда получал какие-то проблемы с синхронизацией по дороге со статикой. При этом вы представляете классический пример общего программирования с использованием шаблонов. Я приму решение на основе шаблонов Rob Copper, представленное в одном из сообщений выше.

0

marxidad Просто быстро следует отметить, Джастин уже сказал, что SQL сильно варьируется в зависимости от типа, так что я работал на том основании, что это может быть что-то полностью отличается в зависимости от типа, следовательно, делегирования это подклассы, о которых идет речь. В то время как ваше решение соединяет SQL ОЧЕНЬ плотно к типу (то есть - SQL).

rptony Хорошая точка на возможные проблемы синхронизации с статики, один я не упомянул, так что спасибо :) Кроме того, его Роб Купер (не медь) BTW;): D (EDIT: Просто подумал я упомянул бы, что в случае, если это не было опечатка, я думаю, это не проблема!)

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