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

Есть ли преимущество или недостаток, когда один конструктор реализует другой?

Если у меня есть класс вроде этого:

public class Foo
{
    public IEnumerable<Bar> Bars { get; set; }

    public Foo()
    {
        Bars = new List<Bar>();
    }
}

На каком-то этапе я переопределяю класс и добавляю вторичный конструктор, который реализует первый такой:

public class Foo
{
    public IEnumerable<Bar> Bars { get; set; }

    // some more properties were added

    public Foo()
    {
        Bars = new List<Bar>();
    }

    public Foo(string parameter): this()
    {
        .... some code here
    }
}

Я мог бы также написать это, похожее на это:

public class Foo
{
    public IEnumerable<Bar> Bars { get; set; }

    // some more properties were added too

    public Foo()
    {
        InitilizeFoo();
    }

    public Foo(string parameter)
    {
        InitilizeFoo();
        .... some code here
    }

    private void InitializeFoo()
    {
        Bars = new List<Bar>();
    }
}

Увидев оба подхода в этом сценарии, есть ли преимущество или недостаток в использовании одного из них?

Является ли наследование конструкторов более эффективным и делает этот код более быстрым или есть недостаток, который я не знаю о том, чтобы сделать вторую реализацию более эффективной?

4b9b3361

Ответ 1

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

Например:

public class Foo
{
    private readonly int myNumber;

    public Foo() : this(42)
    {
    }

    public Foo(int num)
    {
        myNumber = num;
    }
}

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

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

UPDATE. Я выполнил 10 000 000 итераций каждого способа (метод приватной приватизации), и результаты были настолько близки, что были почти неразличимы:

Initializer Method took: 84 ms for 10,000,000 iterations, 8.4E-06 ms/each.
Chained Constructors took: 81 ms for 10,000,000 iterations, 8.1E-06 ms/each.

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

Ответ 2

Конструкторы цепочек - хороший способ обеспечить выполнение SRP и программ. Скрытие кода инициализации внутри автономной функции Initialize() может иметь смысл, если в жизненном цикле объекта есть другие ситуации, где вы также можете захотеть "инициализировать" его; возможно, если вы захотите быстро создать экземпляр и выполнить ленивую инициализацию. Но если единственное допустимое время в жизненном цикле для выполнения этой функции во время создания экземпляра, а инициализация - это четко определенный набор дискретных шагов, которые необходимо выполнить по порядку, тогда цепочка облегчает это.

Ответ 3

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

Ответ 4

Преимущество функции Initialise() заключается в том, что вы хотели бы reset ваш объект - вы можете просто вызвать функцию init снова, а не удалять и воссоздавать объект.

Ответ 5

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

public Foo(string parameter = null)
{

}

У меня были случаи, когда у меня было 10 - 15 необязательных параметров, и, по моему мнению, не было 15 различных конструкторов. Я думаю, что параметры по умолчанию были повторно введены только в платформе 4.0.