2013-06-26 3 views
38

Я недавно изучал инициализатор объектов на C#, но теперь мне интересно, как это работает, когда оно конфликтует с конструктором.Constructor vs Object Initializer Precedence в C#

public class A 
{ 
    public bool foo { get; set; } 
    public A() 
    { 
     foo = true; 
    } 
    public A(bool bar) 
    { 
     foo = bar; 
    } 
} 

Что происходит, когда я пытаюсь это сделать?

public class B 
{ 
    a = A() {foo = false}; 
    b = A(true) {foo = false}; 
} 

Является ли по умолчанию в конструкторе хороший способ иметь bool, который начинается истинный и может быть изменен?

public A(bar=true) 
{ 
    foo = bar; 
} 
+18

Попробуйте ваш пример. –

+3

Код всего, что только что нажал, запустил – Jonesopolis

+0

. Да, он по-прежнему действителен с инициализатором по умолчанию, но если вы хотите более одного параметра, параметры (ы), которые вы можете забыть, это только параметр (ы) хвоста. – arifnpm

ответ

35

От documentation:

Компилятор процессы объект инициализаторы при первом обращении конструктор экземпляра по умолчанию , а затем обработки члену инициализацию.

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

Для второй части вашего вопроса: это скорее вопрос стиля, но если у вас есть ключевое свойство, я бы не создал конструктор со значением по умолчанию. Сделать код клиента установленным значением явно. Я также не уверен, зачем делать что-то вроде этого: b = A(true) {foo = false}; было бы хорошей идеей, если вы не участвуете в конкурсе по обфускации кода.

бит предостережения, хотя:

... если конструктор по умолчанию объявляется как частное в классе, объект инициализаторы, которые требуют открытого доступа не удастся.

15

Конструктор происходит сначала, а затем инициализатор объекта. Только помните, что

a = new A() { foo = false }; 

такой же, как

var temp = new A(); 
temp.foo = false; 
a = temp; 
+0

Они не то же самое. 'a = новый A(); a.foo = false; 'оставляет объект наполовину инициализированным, если исключение было выбрано при предоставлении значений его свойствам. И использование членов объекта даст неожиданный результат (они будут использовать значения по умолчанию для базовых типов, например false для boolean members) вместо того, чтобы бросать NullReferenceException. С другой стороны, с помощью Object Initializer или Object constructors убедитесь, что если возникло исключение, объект не будет инициализирован и предоставит NullReferenceException, если мы попытаемся использовать его член (поскольку он никогда не был инициализирован). – WaelAlshabani

+2

@WaelAlshabani Да, существует временный объект, который создается, а затем свойство присваивается ему, прежде чем его ссылка назначается переменной. И да, это тонкая, но важная разница, если ваше свойство может вызвать исключение, и вы планируете его поймать и по какой-то причине по-прежнему используете ссылку, назначенную переменной. Но ничто из этого не касается этого точного примера. Но я уточню, чтобы сделать это более ясным. – juharr

11
b = new A(true) {foo = false}; 

эффективно короток для:

A temp = new A(true); 
temp.foo = false; 
A b = temp; 

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

2

По сути то, что Павел уже связаны между собой:

С C# 5 language specification (7.6.10.1)

Processing of an object creation expression that includes an object initializer or 
collection initializer consists of first processing the instance constructor and then 
processing the member or element initializations specified by the object initializer or 
collection initializer. 
24

Инициализаторы объектов просто синтаксический сахар, в Уре скомпилированной сборки IL они переводят на отдельные заявления, проверьте его на ILSpy.

enter image description here