Вопрос

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

Что мне нужно, так это набор "вспомогательных" классов, каждый из которых имеет свои собственные статические методы, так что, если я получу объекты A, B и C от стороннего поставщика, у меня могут быть вспомогательные классы с такими методами, как

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

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

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

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

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

Это было полезно?

Решение

Глядя на ваш ответ Я думаю примерно в следующем направлении:

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

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

Другие советы

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

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

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

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

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

По моему опыту работы с такого рода "блокпостами", проблема заключается не в ограничениях языка, а в ограничениях моего дизайна..

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

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

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

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

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

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

В 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())); 
     }
 }

Как мне опубликовать отзыв о Stack Overflow?Отредактировать мой оригинальный пост или опубликовать "ответ"?В любом случае, я подумал, что это могло бы помочь привести пример того, что происходит в AHelper.RetrieveByID() и BHelper.RetreiveByID()

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

Итак, AHelper.RetrieveByID(идентификатор строки) может выглядеть следующим образом

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top