[23/05/2016 21:05:32] <Folco> Comment fait-on une affectation d'objet en C# (genre MonObjet a = b;Autant les bouquins de C++ que j'ai insistent lourdement sur le constructeur de copie et l'opérateur d'affectation, autant j'ai rien vu passer là-dessus en C#.
) ? Il faut explicitement définir l'opérateur = ? J'y pense que maitenant, mais j'ai rien lu dessus.[23/05/2016 21:06:10] <Folco> Ou plutôt, faire un constructeur de recopie ? MonObjet a = new MonObject(b);
Un type référence, à la différence d’un type valeur, doit être instancié grâce au mot clé new.Ca veut dire qu'on ne peut pas avoir d'objet local ??
Folco (./63) :C'est normal, l'intérêt d'un langage avec garbage collector c'est de ne pas recopier les objets et laisser le GC s'occuper de leur gestion à ta place. Copier des objets est assez (très) rare normalement, mais si tu en as vraiment besoin je pense avoir vu plus souvent des méthodes "Clone()" que des constructeurs par copie.
Autant les bouquins de C++ que j'ai insistent lourdement sur le constructeur de copie et l'opérateur d'affectation, autant j'ai rien vu passer là-dessus en C#.
Folco (./63) :Non, en effet. Un objet sera toujours* alloué sur le tas, et un type valeur toujours sur la pile.
Ca veut dire qu'on ne peut pas avoir d'objet local ??
Folco (./63) :Exactement, et normalement c'est ce dont tu devrais avoir besoin 99% du temps. Copier un objet est coûteux**, et à partir du moment où tu paies le prix d'un garbage collector autant l'utiliser à fond et en profiter pour limiter les recopies d'objets.
Dois-je comprendre que le MonObjet a = b; dont je parle dans le premier quote ne crée alors qu'une référence a, référençant le même objet que b, et ne créant pas de nouvelle instance de l'objet ?
Folco (./63) :Tu peux voir ton expression comme un raccourci d'écriture pour string s = new string("abcde");, et ta string (qui est un type référence) se retrouve bien sur le tas.
edit -> si on peut écrire string s = "abcde";, c'est qu'on peut déclarer un objet en local... Du coup, que signifie exactement le = dans cette expression ? A gauche, j'ai une référence typée, à droite j'ai un argument de constructeur d'objet...
Zeph (./64) :Le problème, c'est que c'est un piège très vicieux dans ces langages (et c'est vrai quel que soit le langage de ce type: Java, Python, C#, VB.NET, VB classique etc.). Ça arrive très couramment qu'on modifie accidentellement un objet original quand on veut en fait modifier une copie. Ça m'est déjà arrivé (en Java) alors que je connais le problème depuis longtemps (depuis l'époque où j'ai fait du VB). Et j'ai à plusieurs reprises vu et corrigé cette erreur dans le code d'autrui. Et même le mot-clé const (ou final en Java), quand il existe, n'aide pas, parce qu'il protège seulement la référence et non pas l'objet lui-même. À mon avis, les pointeurs explicits (avec copie de l'objet interdite, cf. QObject) et/ou le partage implicit / copie à l'écriture (comme pour les classes de données de Qt) sont beaucoup plus intuitifs.Folco (./63) :Exactement, et normalement c'est ce dont tu devrais avoir besoin 99% du temps. Copier un objet est coûteux**, et à partir du moment où tu paies le prix d'un garbage collector autant l'utiliser à fond et en profiter pour limiter les recopies d'objets.
Dois-je comprendre que le MonObjet a = b; dont je parle dans le premier quote ne crée alors qu'une référence a, référençant le même objet que b, et ne créant pas de nouvelle instance de l'objet ?
str = "Hello world": str = str.Replace("world", "void");
a = "A"; b = "A"; if (a == b) Console.WriteLine("Yippeee");est vrai, car les types strings sont comparés comme des types valeurs, et non des références.
Warpten (./71) :Alors ton code fonctionne parce que "==" sur les strings compare leurs valeurs, donc bien sûr ça donne le résultat attendu.
De plus
a = "A";
b = "A";if (a == b) Console.WriteLine("Yippeee");est vrai, car les types strings sont comparés comme des types valeurs, et non des références.
Zeph (./72) :
Alors ton code fonctionne parce que "==" sur les strings compare leurs valeurs, donc bien sûr ça donne le résultat attendu.
Zeph (./74) :Immutable, ça veut bien dire ça ? https://fr.wikipedia.org/wiki/Objet_immuable Ca veut donc dire qu'on peut pas modifier le contenu d'une chaine ? Est-ce que ça en fait un objet constant, au sens C++ ?
Le type string est un type référence, il est immutable
flanker (./70) :Ça arrive pourtant très vite, genre:
très couramment ? je n'ai pas souvenir avoir eu ce genre de bugs
public class Foo {
public int x; // public pour l'exemple, ce serait la même chose avec get/set
}
public class Bar {
private final Foo myFoo;
Bar() {
myFoo = new Foo();
myFoo.x = 1;
}
Foo getMyFoo() {
return myFoo;
}
}
public class Baz {
doSomething(Foo foo) {
foo.x = 2;
}
}
public class Toto {
public static void main (String[] args) {
Bar bar = new Bar();
Foo foo = bar.getMyFoo();
new Baz().doSomething(foo); // et vlan!
// Maintenant, bar.myFoo a x == 2, et le code de Bar risque de foirer à fond.
}
}
(cet exemple devrait compiler en Java si on crée les fichiers qu'il faut, peut-être même aussi en C#, je ne sais pas, mais en tout cas, le problème est le même en C#).Zeph (./77) :La différence, c'est qu'un objet immuable l'est dans tous les contextes (c'est une propriété de la classe), alors qu'un objet C++ peut être muable dans la classe (ou fonction etc.) à laquelle il appartient et const pour le reste du code (il suffit de le retourner avec le mot-clé const). Une classe C++ peut avoir des méthodes const et non-const, dont seules les premières sont utilisables dans un contexte const, en Java ou C#, toute la classe doit être immuable, ce qui restreint beaucoup les cas d'usage de cette construction.
Oui, c'est quasiment la même notion que "const" en C++ : ça veut simplement dire que tu ne peux pas modifier le contenu de l'objet.
Warpten (./82) :C'est la même chose avec final en Java, mais ce n'est pas suffisant. On ne peut pas rendre tout immuable, du moins pas sans devoir recopier des objets énormes de partout. Et si un objet représente une ressource externe muable, un objet immuable est une représentation pas du tout appropriée.
On peut "tricher" en c# en déclarant du readonly où il faut (ça ne devient assignable que dans le constructeur). Les conteneurs sont exclus puisqu'on ne les assigne pas, on ne fait que les remplir.
int? i = 0; if (i is object) { Console.WriteLine("C'est un objet"); }Le programme que j'ai élaboré a établi de manière formelle que i est un objet.