Сведения о вопросе

FUTER

08:20, 10th August, 2020

Статические методы в интерфейсе / абстрактном классе

Просмотров: 476   Ответов: 10

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

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

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

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

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

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

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



  Сведения об ответе

darknet

18:32, 22nd August, 2020

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


  Сведения об ответе

ЯЯ__4

10:53, 17th August, 2020

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

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

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


  Сведения об ответе

PAGE

13:10, 11th August, 2020

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

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


  Сведения об ответе

9090

21:06, 1st October, 2020

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

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

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


  Сведения об ответе

ASSembler

04:04, 3rd August, 2020

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

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

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


  Сведения об ответе

lesha

06:09, 29th August, 2020

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

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

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


  Сведения об ответе

nYU

11:30, 25th August, 2020

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


  Сведения об ответе

screen

21:06, 1st October, 2020

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

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

Итак, AHelper.RetrieveByID(string 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];
}

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

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


  Сведения об ответе

DINO

08:56, 13th August, 2020

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


  Сведения об ответе

Chhiki

20:19, 6th August, 2020

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

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


Ответить на вопрос

Чтобы ответить на вопрос вам нужно войти в систему или зарегистрироваться