Что делают фигурные скобки после нового оператора C #? - PullRequest
59 голосов
/ 27 октября 2010

Учитывая приведенный ниже код, в чем разница между способом инициализации position0 и способом инициализации position1?Они эквивалентны?Если нет, то в чем разница?

class Program
{
    static void Main(string[] args)
    {
        Position position0 = new Position() { x=3, y=4 };

        Position position1 = new Position();
        position1.x = 3;
        position1.y = 4;
    }
}

struct Position
{
    public int x, y;
}

Ответы [ 7 ]

58 голосов
/ 27 октября 2010

Они не вполне эквивалентны - по крайней мере, не в общем случае.Код, использующий инициализатор объекта, ближе к этому:

Position tmp = new Position();
tmp.x = 3;
tmp.y = 4;
Position position1 = tmp;

Другими словами, присвоение переменной происходит только после свойства были установлены.Теперь в случае, когда вы объявляете новую локальную переменную, это на самом деле не имеет значения, и компилятор вполне может оптимизировать вашу первую форму.Но по логике это имеет значение.Рассмотрим:

Position p1 = new Position { x = 10, y = 20 };

p1 = new Position { x = p1.y, y = p1.x };

Если бы это сделало присваивание p1 first , вы бы получили 0 для p1.x и p1.y.В то время как на самом деле это эквивалентно:

Position tmp = new Position();
tmp.x = 10;
tmp.y = 20;
Position p1 = tmp;

tmp = new Position();
tmp.x = p1.y; // 20
tmp.y = p1.x; // 10
p1 = tmp;

РЕДАКТИРОВАТЬ: я только что понял, что вы используете структуру, а не класс.Это может иметь некоторые тонкие различия ... но вы почти наверняка не должны использовать изменяемую структуру для начала:)

46 голосов
/ 27 октября 2010

Инициализаторы объектов и коллекций, используемые для инициализации полей объекта.

http://msdn.microsoft.com/en-us/library/bb384062.aspx

Они производят почти эквивалентный IL. У Джона Скита есть ответ о том, что на самом деле происходит.

7 голосов
/ 27 октября 2010

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

Обратите внимание, что существует небольшая проблема с синхронизацией, которая может быть полезна;с инициализаторами все назначения / добавления происходят до переменной, которая может помочь остановить другие потоки, видящие незавершенный объект.В противном случае вам потребуется дополнительная переменная для достижения того же результата.

2 голосов
/ 27 октября 2010

Забыть обо всем, что связано с IL, это просто сокращенная запись.Что вы делаете, это:

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

b.С другой стороны, вы используете новый синтаксис инициализатора, который неявно заставляет компилятор делать то, что вы делали в случае, если, несмотря на все подмножества.

IL, они достигнут того же для вас.

2 голосов
/ 27 октября 2010

Ваши два примера кода будут генерировать идентичный IL.(По крайней мере, в сборках релиза)

1 голос
/ 27 октября 2010

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

Также рассмотрим случай, когда вы хотите передать новый объект куда-то еще:

var aList = new List<Position>();
aList.Add( new Position() { x=3, y=4 } );
1 голос
/ 27 октября 2010

Это полностью эквивалентно.Фактически, компилятор просто преобразует первую версию во вторую.

Единственное отличие между ними состоит в том, что с первой вы можете делать хорошие вещи, например, передавать инициализированную версию методу:

DoSomethingWithPoint(new Position() { x=3, y=4 });

Это намного больше строк кода, чем во втором примере инициализации.

...