septembre
2007
J’ai été surpris de constater, quand j’ai commencé à regarder C# 3.0, que les object initializers passaient par une variable intermédiaire.
Ce matin, j’ai pensé à une possible explication.
L’instruction suivante :
c = new C { I1 = 1, I2 = 2 };
correspond à une seule instruction, même si elle sera traduite en 4 par le compilateur :
<>g__initLocal0.I1 = 1;
<>g__initLocal0.I2 = 2;
c = <>g__initLocal0;
Cette varaiable intermédiaire joue le rôle d’une transcation.
Si on ne passait pas par elle, et que l’initialisation d’une des propriétés génère une exception catchée, on aurait un objet à moitié initialisé.
{
public int I1 { get; set; }
private int _i2;
public int I2
{
get { return _i2; }
set { throw new Exception(); }
}
}
C c = null;
try
{
c = new C { I1 = 1, I2 = 2 };
}
catch (Exception)
{
}
Dans ce cas là, c = null alors que sans la variable intermédiaire, on aurait
c = new C { I1 = 1 }
De plus, sans la variable intermédiaire, on aurait
new C { I1 = 1, I2 = 2 }
différent de
new C { I2 = 2, I1 = 1 }
Avec la variable intermédiaire, les object initializers sont commutatifs.
Merci Matthieu pour cet éclaircissement. Il s’agit d’un parti pris par l’équipe C#. On peut le comprendre par le fait que la plupart du temps, tout se fait en mode managé. Par contre, si on utilise un objet COM dans notre objet ou un objet à « disposer », on évitera les initialiseurs…
Merci.
Non ce n’est pas du chipotage, tu as raison.
Ca n’a pas d’intérêt en effet, c’est juste pour la démo
Mais plus généralement, des appels de fonction successifs n’ont pas de raison d’être commutatifs. Les propriétés n’étant que des appels de fonction déguisés, je t’accorde qu’on peut s’emmeler.
J’ai l’air de chipoter, mais j’apprécie beaucoup ce blog
Tu as bien sûr raison dans le cas où le set de I1 modifie la valeur de I2 (ou inversement) ou l’utilise comme dans ton exemple.
Je n’y avais pas pensé quand j’ai posté.
En revanche, dans ce cas, ça marche :
{ <br />
public int I1 { get; set; } <br />
private int _i2; <br />
public int I2 <br />
{ <br />
get { return _i2 + I1; } <br />
set { _i2 = value; } <br />
} <br />
}
Par contre je pense que dans ton exemple, tu voulais mettre
par ce que
je vois pas trop l’intérêt.
Bonjour !
je ne pense pas que les object initializers puissent être commutatifs :
class C
{
public int I1 { get; set; }
private int _i2;
public int I2
{
get { return _i2; }
set { _i2 = I1 + 1; }
}
}
Je n’ai pas de compilo sous la main, mais new C { I1 = 1, I2 = 2 } doit être différent de new C { I2 = 2, I1 = 1 }, non ?