Как я могу вызвать оба инициализатора конструктора, base () и this ()? - PullRequest
29 голосов
/ 17 июля 2011

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

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

public partial class TrackTyped : Component
{
    IContainer components = null;

    public TrackTyped()
        : base()
    {
        InitializeComponent();
    }

    public TrackTyped(IContainer container)
        : base()
    {
        container.Add(this);
        InitializeComponent();
    }
}

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

Если я прочитал спецификацию правильно (я только начал пытаться читать спецификацию, поэтому я могу быть не прав):

10.11 Instance Constructors
   constructor-declarator:
      identifier   (   formal-parameter-listopt   )   constructor-initializeropt
   constructor-initializer:
      :   base   (   argument-listopt   )
      :   this   (   argument-listopt   )

Это говорит, что я могу иметь только один из них.

ВОПРОС: означает ли 10.11, что нет необходимости вызывать оба, или это просто подразумевает, что язык поддерживает вызов только одного?

Ответы [ 5 ]

22 голосов
/ 17 июля 2011

Нет необходимости вызывать оба, потому что this перенаправляет на другой конструктор, который вызовет base.

9 голосов
/ 17 июля 2011

Кажется, это то, что вы хотите:

public partial class TrackTyped : Component
{
    IContainer components = null;

    public TrackTyped()
        : base()
    {
        InitializeComponent();
    }

    public TrackTyped(IContainer container)
        : this()
    {
        container.Add(this);
    }
}

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

И вы правильно читаете спецификацию: она должна быть одна или другая.

8 голосов
/ 17 июля 2011

Вы не можете и не можете. Вы можете переслать вызов конструктора другому конструктору того же класса с помощью :this(...). Последний конструктор в этой цепочке должен будет неявно или явно инициализировать базу с помощью :base(...)

Предположим, класс A имеет два конструктора. Один инициализирует базу с :base(2), другой с :base(3). Если первый конструктор мог также указать :this (/*call the other ctor*/), как должна быть инициализирована база: с 2 или 3? Вот почему эти вещи не разрешены

4 голосов
/ 05 апреля 2018

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

public MissingEntityException(Type type, string criteria, string message = "") 
    : this(type, criteria, message, null)
{           
}

public MissingEntityException(Type type, string criteria, string message, Exception innerException) 
     : base(message, innerException) 
{
    this.EntityType = type;
    this.Criteria = criteria;
}

Это поддерживается по всей иерархии и может включать любое число или параметры.

2 голосов
/ 17 июля 2011

это то, что вы ищете?

public partial class TrackTyped : Component
{
    IContainer components = null; 
    public TrackTyped() : base()
    {
        // logic for InitializeComponent() here
    } 

    public TrackTyped(IContainer container) : this()
    {
        container.Add(this)
    }
}

Кстати: это интересное использование для второго ctor:

var a = TrackTyped(container);

Интересно, если удалить второй ctor и сделать этобыло бы понятнее для вас?(тот же конечный результат)

container.Add(new TrackTyped());
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...