2016-08-05 12 views
2

ich mit, dass eine Klasse, hat eine Sammlung-Eigenschaft:auf einer Klassensammel Mitglied initialisieren

class MyClass 
{ 
    public MyCollection Coll { get; private set; } 
    public MyClass() { this.Coll = new MyCollection(); } 
} 

class MyCollection : IList { ... } 

Jetzt bin ich zwei verschiedene Instanzen von meiner Klasse zu erstellen:

var o1 = new MyClass() { Coll = {"1", "2"}}; 
var o2 = new MyClass() { Coll = new MyCollection() {"1", "2"} }; 

Ich verstehe der Compiler beklagt sich über Letzteres, da der Setter für das Objekt nicht existiert (oder in diesem Fall nicht öffentlich zugänglich ist). Die erste jedoch ist eine Zuordnung - wenn auch eine Sammlung Initialisierer.

Ich nehme an, dass Sammlung-Initializer für Get-Only-Eigenschaften zulässig sind, da sie nur Add auf IList aufrufen und den Getter der Eigenschaft nicht tatsächlich aufrufen. Ist das richtig?

+0

Ist 'o1' Lauf, oder sehen Sie einen Laufzeitfehler beim Aufruf von 'Add' auf ein' null' Objekt? – dasblinkenlight

+1

Obwohl als doppelt zu einer [älteren Frage] (http://stackoverflow.com/questions/5646285/c-sharp-object-initialization-of-read-only-collection-properties) zu kennzeichnen, wählen Sie für diese eine viel mehr prägnant. –

Antwort

2

Aus Ihrer Frage:

Ich gehe davon aus, dass Auflistungsinitialisierer ist [...] nur Add auf IList Aufruf von [...].

Diese Annahme ist richtig. Sammlungsinitialisierer sind syntaktische Zucker, die der C# -Compiler während der Kompilierung in etwas expliziter übersetzt. Zum Beispiel die folgende Zeile ein:

var l = new List<int>() { 1, 2 }; 

Ist eigentlich übersetzt:

newobj  List<System.Int32>..ctor // Create list object. 
stloc.0        // Store list object as local variable "0". 
ldloc.0        // Push local variable "0" onto the stack. 
ldc.i4.1        // Push 4-byte integer constant "1" onto the stack. 
callvirt List<System.Int32>.Add // Call "Add" (uses and pops the last two values from 
            // the stack). 
ldloc.0        // Push list onto stack again. 
ldc.i4.2        // Push constant "2" onto stack. 
callvirt List<System.Int32>.Add // Call "Add" again. 

Das bedeutet:

var l = new List<int>(); 
l.Add(1); 
l.Add(2); 

Sie können dies auf der generierten MSIL (etwas vereinfacht) auf der Suche überprüfen werden dass Ihr Code var o1 = new MyClass() { Coll = {"1", "2"}}; niemals auf den privaten Setter zugreift. Es wird einfach Coll und ruft Add darauf wie so:

var o1 = new MyClass(); 
o1.Coll.Add("1"); 
o1.Coll.Add("2"); 

Wieder können wir die MSIL überprüfen Sie diese, um zu überprüfen:

newobj  MyClass..ctor 
stloc.1        // Store MyClass instance at local variable "1". 
ldloc.1        // Load MyClass instance onto stack. 
callvirt MyClass.get_Coll   // Call getter of "Coll" and push the MyCollection 
            // instance onto the stack. 
ldstr  "1"      // Push the string "1" onto the stack... 
callvirt MyCollection.Add   // ...and call "Add". 
pop         // Discard the return value of "Add". 
ldloc.1 
callvirt MyClass.get_Coll 
ldstr  "2" 
callvirt MyCollection.Add 
pop 
+1

Gute Antwort, IL bringt es auf den Punkt. – HimBromBeere

+1

@Abbondanza, Ihre Antwort ist gut, aber die Proben in der Jon Skeet [Antwort] (http://Stackoverflow.com/a/5646336/4295017) sind wahrscheinlich leichter zu absorbieren. Ich schlage vor, die Codebeispiele von Jon in Ihre Antwort einzufügen, um Ihnen eine erschöpfende Antwort auf diese knappe Frage mit einem prägnanten Codebeispiel zu geben. –

+0

@DmitryEgorov, guter Punkt. Ich habe die Antwort erweitert. –

Verwandte Themen