Являются ли конструкторы вложенности (или методы factory) хорошими, или каждый из них выполняет все операции init

Это хорошая идея (из дизайна POV) встраивать вызовы конструктора для перегруженных методов стиля New или Factory? Это в основном для простых конструкторов, где каждая перегрузка основывается на предыдущем.

MyClass( arg1 ) { 
    _arg1 = arg1; 
    _otherField = true; 
    _color="Blue" 
}
MyClass( arg1, arg2) : this(arg1) { 
    _arg2 = arg2  
}
MyClass( arg1, arg2, arg3) : this(arg1, ar2) { 
    _arg3 = arg3; 
}

Или с помощью методов Factory:

static NewInstance(arg1 ) { 
   _arg1 = arg1;       
}
static NewInstance(arg1, arg2) {
   f = NewInstance(arg1);
   f._arg2 = arg2;
}
//... and so on

Я вижу несколько недостатков с обеих сторон

  • Вложение скрывает то, что делает конструктор
  • Не вложенность дублирует всю функциональность

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

Изменить: @Jon Skeet. Теперь я вижу, почему это меня так беспокоило. Я делал это назад! Я написал все это и даже не заметил, это просто пахло. В большинстве других случаев, которые у меня есть (что я написал), делайте это так, как вы рекомендуете, но это, конечно, не единственное, что я сделал так. Я замечаю, что более сложные из них я сделал правильно, но простые, кажется, были неаккуратными. Мне нравятся микроредакции. Мне также нравятся акронимы!

Ответ 1

Я думаю, что разумно объединять конструкторы вместе, но я делаю это по-другому - версия с меньшим количеством параметров вызывает версию с большим количеством параметров. Таким образом, очень ясно, что происходит, и вся настоящая "логика" (за пределами значений по умолчанию) находится в одном месте. Например:

public Foo(int x, int y)
{
    this.x = x;
    this.y = y;
    precomputedValue = x * y;
}

private static int DefaultY
{
    get { return DateTime.Now.Minute; }
}

public Foo(int x) : this(x, DefaultY)
{
}

public Foo() : this(1, DefaultY)
{
}

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

public static XmlDocument FromText(string xml)

public static XmlDocument FromFile(string filename)

Ответ 2

2016 Edit: все еще впереди времени, С# радикально сокращает или устраняет поддержку своих записей и поддержку конструктора по умолчанию для С# 7, возможно, С# 8. Наконец,

2015 Edit. Я был намного опережает время. С# 6 и С# 7 устраняют необходимость в конструкторах.

Если вы работаете в .NET 3.5, я рекомендую никогда не использовать конструкторы. Единственное исключение, которое я оставляю для этого, - это использование конструктора инъекции для инъекции зависимостей. С .Net 3.5 они создали инициализаторы объектов, которые позволяют вам выполнять

var myclass = New MyClass { arg1 = "lala", arg2 ="foo" }

Это приведет к инициализации класса со значениями, назначенными для arg1 и arg2, оставив arg3 как

default(typeof(arg3)).