В чем разница между созданием экземпляра в конструкторе или в определении поля?

В чем разница между этим:

public class Foo {
    private Bar bar;
    public Foo() { bar = new Bar(); }
}

и это:

public class Foo {
    private Bar bar = new Bar();
    public Foo() { }
}

person guhou    schedule 01.08.2010    source источник
comment
stackoverflow.com/questions/24551/   -  person SwDevMan81    schedule 01.08.2010
comment
stackoverflow.com/questions/1157201/   -  person SwDevMan81    schedule 01.08.2010


Ответы (5)


Разница в том, что во втором случае инициализация поля происходит перед конструктором this/base, а в первом случае инициализация происходит внутри конструктора.

person Darin Dimitrov    schedule 01.08.2010
comment
Это просто техническая вещь или есть практические причины в пользу того или иного подхода? Например, если вместо Bar я использовал какой-то контекст данных (например, из структуры сущностей), есть ли практическая разница? - person guhou; 01.08.2010
comment
@BlueM937 BlueM937, если у вас есть несколько конструкторов, возможно, вы дублируете код. - person AndersK; 01.08.2010

CLR не поддерживает такие поля инициализации. Чтобы заставить его работать, компилятор C# переписывает ваш конструктор. Ил выглядит так:

  IL_0000:  ldarg.0
  IL_0001:  newobj     instance void ConsoleApplication1.Bar::.ctor()
  IL_0006:  stfld      class ConsoleApplication1.Bar ConsoleApplication1.Foo::bar
  IL_000b:  ldarg.0
  IL_000c:  call       instance void [mscorlib]System.Object::.ctor()
  IL_0011:  ret

Обратите внимание, что конструктор Bar вызывается перед базовым конструктором Foo. В чем разница с вашим другим фрагментом, там базовый конструктор Foo вызывается потом. Это редко имеет значение, если только поле не унаследовано и конструктор базового класса что-то с ним делает.

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

person Hans Passant    schedule 01.08.2010

Немного констатируя очевидное, но со вторым подходом нет необходимости в конструкторе.

person John Parker    schedule 01.08.2010

Разницы нет, потому что компилятор помещает все определения полей перед кодом конструктора. Так что в IL-коде оба варианта выглядят одинаково.

person Coderik    schedule 01.08.2010

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

person Keith Paul Barrow    schedule 01.08.2010