c# - полей - свойства конструктора




Конструкторы C#с одинаковыми сигнатурами параметров (5)

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

public Thing(string connectionString)

public Thing(string fileName)

Очевидно, это не допускается, потому что подписи одинаковы. Кто-нибудь знает об изящном решении этой проблемы?


Мне нравятся статические конструктор-функции:

class Thing
{
   public static Thing NewConnection(string connectionString)
   {
       return new Thing(connectionString, true);
   }

   public static Thing NewFile(string fileName);
   {
        return new Thing(fileName, false);
   }
}
.
.
.
{
    var myObj = Thing.NewConnection("connect=foo");
    var Obj2 = Thing.NewFile("myFile.txt");
}

(не показано, но прямолинейно, реализация Thing-Constructor с дополнительным булевым параметром).


Вот некоторые способы обхода.

Имейте один конструктор, который берет строку соединения, а затем имеет фабричный метод в классе, который принимает имя файла. Что-то вроде этого:

public static Thing CreateThing(string fileName)

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

Другой вариант - иметь перечисление, в котором есть два типа. FileName и ConnectionString. Тогда просто один конструктор, который берет строку, и перечисление. Затем на основе перечисления вы можете определить, к какому пути идти.


Ну, есть несколько потенциалов - то, что считается элегантным, зависит от сценария использования.

  • Статические методы фабрики, которые вызывают в частный конструктор.

    static Thing thingWithFileName(string fileName)
  • Создайте другой тип для одного из параметров или используйте встроенный. Вместо файла stringName вы можете использовать System.IO.FileStream. Это также более безопасно для типов, поскольку я не могу случайно передать неверные данные в неправильный статический метод или в поле.

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

    enum ThingType { FileName, ConnectionString }
    Thing(string str, ThingType type) ...
  • Subclass Thing, поэтому у вас есть ConnectionTypeThing и FileBackedThing

  • Полностью устраните Thing, делающее это соединение, и предустановленные источники данных. Таким образом, вы получаете

    Thing(InputStream dataSource)

    или что-то подобное.

Моя «элегантность» денег идет либо на первое, либо на второе предложение, но мне нужно больше контекста, чтобы быть счастливым с любым выбором.


Они на самом деле кажутся мне разными «вещами», либо классом, связанным с файлом, либо классом, связанным с базой данных. Я бы определил интерфейс, а затем имел отдельные реализации для каждого. Используйте Factory для создания правильной реализации.

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

public interface IThing
{
   ... methods to do the things that Things do
}

public class FileThing : IThing
{
  ... file-based methods
}

public class DatabaseThing : IThing
{
  ... database-based methods
}

public static class ThingFactory
{
     public IThing GetFileThing( string name )
     {
         return new FileThing( name );
     }

     public IThing GetDatabaseThing( string connectionString )
     {
         return new DatabaseThing( connectionString );
     }
}

Если бы у вас было общее поведение, вы могли бы альтернативно определить абстрактный класс, содержащий поведение по умолчанию / общее поведение и извлечь из него вместо / в дополнение к интерфейсу.


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

public class Thing
{
    private string connectionString;

    private string filename;

    private Thing()
    {
        /* Make this private to clear things up */
    }

    public static Thing WithConnection(string connectionString)
    {
        var thing = new Thing();
        thing.connectionString = connectionString;
        return thing;
    }

    public static Thing WithFilename(string filename)
    {
        var thing = new Thing();
        thing.filename = filename;
        return thing;
    }
}




.net