[C#] So erstellen Sie eine Referenztyp-Eigenschaft "readonly"


Answers

Leider ist es in C # im Moment nicht einfach. Du könntest den "Nur-Lese-Teil" von Foo in einer Schnittstelle extrahieren und deine Property anstelle von Foo .

Question

Ich habe eine Klasse Bar mit einem privaten Feld, das den Referenztyp Foo . Ich möchte Foo in einer öffentlichen Eigenschaft offenbaren, aber ich möchte nicht, dass die Verbraucher der Immobilie Foo ändern können ... Es sollte jedoch intern durch Bar readonly , dh ich kann das Feld nicht readonly .

Also was ich möchte ist:

      private _Foo;

      public Foo 
      { 
         get { return readonly _Foo; } 
      } 

... das ist natürlich nicht gültig. Ich könnte einfach einen Klon von Foo (ich nehme an, dass es IClonable ), aber das ist für den Verbraucher nicht offensichtlich. Sollte ich den Namen der Eigenschaft zu FooCopy ? Sollte es stattdessen eine GetCopyOfFoo Methode sein? Was würdest du als beste Praxis ansehen? Vielen Dank!




Ich dachte über ähnliche Sicherheitsmaßnahmen nach. Es gibt wahrscheinlich einen Weg. Ganz klar, aber nicht kurz. Die allgemeine Idee ist ziemlich einfach. Aber ich habe immer ein paar Wege gefunden, also habe ich es nie getestet. Aber Sie könnten es überprüfen - vielleicht wird es für Sie arbeiten.

Das ist Pseudo-Code, aber ich hoffe, die Idee dahinter ist klar

public delegate void OnlyRuller(string s1, string s2);
public delegate void RullerCoronation(OnlyRuller d);

class Foo {
  private Foo();
  public Foo(RullerCoronation followMyOrders) {
     followMyOrders(SetMe);
  }

  private SetMe(string whatToSet, string whitWhatValue) {
     //lot of unclear but private code
  }
}

Also in Klasse, die diese Eigenschaft erstellt haben Sie Zugriff auf SetMe-Methode, aber es ist immer noch privat, so dass außer Creator Foo aussieht unveränderlich.

Bei allem, was größer ist als ein paar Eigenschaften, wird das wahrscheinlich bald zu einem Chaos werden - deshalb habe ich immer andere Arten der Verkapselung bevorzugt. Wenn es jedoch sehr wichtig für Sie ist, dem Kunden nicht zu erlauben, Foo zu ändern, dann ist dies eine Alternative.

Wie gesagt, das ist nur Theorie.




Um Jon Skeets Kommentar zu verdeutlichen, können Sie eine Ansicht erstellen, die eine unveränderliche Wrapper-Klasse für das veränderbare Foo darstellt. Hier ist ein Beispiel:

class Foo{
 public string A{get; set;}
 public string B{get; set;}
 //...
}

class ReadOnlyFoo{
  Foo foo; 
  public string A { get { return foo.A; }}
  public string B { get { return foo.B; }}
}



Das "Klonen" der Foo-Objekte, die Sie erhalten und zurückgeben, ist eine normale Praxis, die als defensives Kopieren bezeichnet wird . Wenn es beim Klonen keine unsichtbaren Nebeneffekte gibt, die für den Benutzer sichtbar sind, gibt es absolut keinen Grund, dies NICHT zu tun. Es ist oft die einzige Möglichkeit, die internen privaten Daten Ihrer Klassen zu schützen, besonders in C # oder Java, wo die C ++ - Idee von const nicht verfügbar ist. (IE, es muss getan werden, um wirklich unveränderliche Objekte in diesen beiden Sprachen zu erzeugen.)

Nur um zu klären, mögliche Nebenwirkungen wären Dinge wie Ihr Benutzer (vernünftigerweise) erwartet, dass das ursprüngliche Objekt zurückgegeben wird, oder eine Ressource von Foo gehalten wird, die nicht korrekt geklont wird. (In welchem ​​Fall, was macht es, IClonable zu implementieren ?!)