Конструкторы С# с одинаковыми сигнатурами параметров
Я уверен, что это должна быть общая проблема. У меня есть класс, который в идеальном мире имел бы следующие конструкторы
public Thing(string connectionString)
public Thing(string fileName)
Очевидно, это недопустимо, потому что подписи одинаковы. Кто-нибудь знает об изящном решении этой проблемы?
Ответы
Ответ 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 с дополнительным логическим параметром).