Подтвердить что ты не робот

Конструкторы С# с одинаковыми сигнатурами параметров

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

public Thing(string connectionString)

public Thing(string fileName)

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

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

    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)
    

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

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

Ответ 3

Вы можете сделать все конструкторы частными и создать методы factory (статические методы в классе, например CreateFromConnectionString()).

Ответ 4

На самом деле они кажутся мне разными "вещами", либо классом, связанным с файлом, либо классом, связанным с базой данных. Я бы определил интерфейс, а затем имел отдельные реализации для каждого. Используйте 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 );
     }
}

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

Ответ 5

Сделайте два общедоступных свойства ConnectionString и FileName, а затем используйте их для заполнения вашего объекта.

В С# вы можете использовать объект initalizer. Вот так:

Thing thing = new Thing{FileName = "abc", ConnectionString = "123"};

Ответ 6

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

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

public static Thing CreateThing(string fileName)

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

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

Ответ 7

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

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 с дополнительным логическим параметром).