web-dev-qa-db-fra.com

Que font les accolades après la nouvelle instruction C #?

Étant donné le code ci-dessous, quelle est la différence entre la façon dont position0 est initialisé et la façon dont position1 est initialisé? Sont-ils équivalents? Sinon, quelle est la différence?

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;
}
59

Initialiseurs d'objets et de collections, utilisés pour initialiser des champs sur un objet.

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

Ils produisent presque IL équivalent. Jon Skeet a la réponse sur ce qui se passe vraiment.

46
Joshua Rodgers

Ils ne sont pas tout à fait équivalents - du moins pas dans le cas général. Le code utilisant un initialiseur d'objet est plus proche de cela:

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

En d'autres termes, l'affectation à la variable se produit uniquement après les propriétés ont été définies. Maintenant, dans le cas où vous déclarez une nouvelle variable locale, cela n'a pas vraiment d'importance, et le compilateur peut très bien optimiser votre première forme. Mais logiquement, cela compte. Considérer:

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

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

Si cela a fait l'affectation à p1premier, vous vous retrouveriez avec 0 pour les deux p1.x et p1.y. Alors que cela équivaut en fait à:

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;

EDIT: Je viens de réaliser que vous utilisez une structure plutôt qu'une classe. Cela peut faire quelques différences subtiles ... mais vous ne devriez certainement pas utiliser une structure mutable pour commencer :)

58
Jon Skeet

Il s'agit d'un initialiseur d'objet et vous permet simplement d'affecter des valeurs dans une seule expression. Plus important encore, cela fonctionne également dans LINQ an pour les types anonymes (autrement immuables). Il existe également une syntaxe d'initialisation de collection similaire pour les éléments addi des nouvelles collections.

Notez qu'il existe un problème de synchronisation subtil qui peut être utile; avec les initialiseurs, les affectations/ajouts se produisent tous avant la variable est affectée, ce qui peut empêcher les autres threads de voir un objet incomplet. Sinon, vous auriez besoin d'une variable supplémentaire pour obtenir le même résultat.

7
Marc Gravell

Oublier tous les trucs IL, c'est juste une notation abrégée. Voici ce que vous faites:

une. Dans un cas, vous utilisez explicitement le constructeur par défaut, puis définissez les deux propriétés.

b. Dans l'autre, vous utilisez la nouvelle syntaxe de l'intialiseur qui oblige implicitement le compilateur à faire ce que vous avez fait dans le cas a.

Nonobstant les subtilités IL, elles réaliseront la même chose pour vous.

2
awrigley

Vos deux exemples de code généreront un IL identique. (Au moins dans les versions Release)

2
SLaks

Ce sont entièrement équivalents. En fait, le compilateur transforme simplement la première version en seconde.

La seule différence entre les deux est qu'avec le premier, vous pouvez faire de Nice Thins, comme passer la version initialisée à une méthode:

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

C'est beaucoup plus de lignes de code que le deuxième exemple d'initialisation.

1
Pieter van Ginkel

Ils sont équivalents, sauf que l'un est plus facile à lire que l'autre.

Considérez également le cas lorsque vous souhaitez passer le nouvel objet ailleurs:

var aList = new List<Position>();
aList.Add( new Position() { x=3, y=4 } );
1
Dan Byström