Можно ли ссылаться на это в конструкторе?

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

Конструктор для MyForm:

MyForm()
{
   _MyFormCalcs = new MyFormCalcs(this);
}

Но сегодня я столкнулся с ошибкой, из-за которой я подумал, что, поскольку мой конструктор не завершил работу, он создает новый экземпляр MyForm для передачи в MyData. Таким образом, он дважды вызывает конструктор. Я обнаружил, что статический список в MyFormCalcs заполнялся дважды и во второй раз терпел неудачу, поскольку ключи уже присутствовали в списке.

Могу ли я использовать это в конструкторе для ссылки на этот экземпляр? Что он будет содержать в нижнем классе — запустился конструктор или нет.

Как лучше сдать форму в низший класс?


person Peter    schedule 23.02.2011    source источник


Ответы (4)


Нет, это не создаст новый экземпляр MyForm.

В общем, разрешение this «убегать» из конструктора dangerous, так как это означает, что его можно использовать до завершения конструктора, но он не будет создавать новый экземпляр. Если бы вы могли привести краткий, но полный пример проблемы, с которой вы столкнулись, мы могли бы помочь диагностировать ее дальше. В частности, неясно, что вы имеете в виду под "статическим списком, заполняемым дважды". Обычно не рекомендуется заполнять статическую переменную в конструкторе экземпляра.

person Jon Skeet    schedule 23.02.2011
comment
Согласен, а также, если вы можете убедиться, что это последний оператор для выполнения, не должно быть никаких других проблем. - person Adriaan Stander; 23.02.2011
comment
@astander: Ну, кроме этого, обычные гарантии модели памяти .NET не применялись ... маловероятно, что вы укусите, но все же возможно. - person Jon Skeet; 23.02.2011
comment
Да, лучше перестраховаться, чем сожалеть X-) - person Adriaan Stander; 23.02.2011
comment
@Jon: Иногда это опасно, но иногда не так много других доступных вариантов ... для отношений родитель-потомок (или отношений контейнер-контейнер), где и родителю, и дочернему элементу нужны ссылки друг на друга, чтобы быть действительными объекты, нет никаких способов обойти это. :\ - person user541686; 23.02.2011
comment
@astander: Вы не можете гарантировать, что ваш класс является подклассом. - person user541686; 23.02.2011
comment
@Mehrdad: Да, с этим может быть сложно справиться, но это запах дизайна, которого следует избегать, если это возможно. Однако он определенно не начнет неявно вызывать конструкторы, как опасается ОП :) - person Jon Skeet; 23.02.2011

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

class MyClass
{

 var obj:SomeClass;

  public MyClass()
  {
  }

  public Init()
  {
    obj = SomeClass(this);
  }

}
person Alexander Sobolev    schedule 23.02.2011

Создайте частное свойство, которое создает экземпляр MyFormCalcs только при первом использовании, например:

public class MyForm {

  private MyFormCalcs MyFormCalcs {
    get {
      _MyFormCalcs = _MyFormCalcs ?? new MyFormCalcs(this);   
    }
  }
}

Таким образом, вам не нужно думать о том, когда что-то «инициализировать».

person pero    schedule 23.02.2011

Вот очень полный ответ порядка конструктора С#:

порядок выполнения конструктора C#

person xanatos    schedule 23.02.2011