2010-07-22 4 views
19

ich viel Beispielcode gesehen habe geschrieben, wie etwas mit (bitte verzeihen Sie, wie schrecklich der Dose ist dies):Private ‚gesetzt‘ in C# - Probleme, mein Gehirn Umwickeln es

public class Test 
{ 
    public object Thingy { get; private set; } 
} 

Leider diese Arten von Beispielen erklären nie wirklich, warum 'set' als privat gesetzt ist. Ich frage mich also, ob es ein gutes, allgemeines Beispiel gibt, das mir zeigt, warum so etwas verwendet wird.

Ich sehe es - die Eigenschaft kann ausgeführt werden, um einige zusätzliche Logik zusätzlich zu diesem Feld zu verarbeiten. Ich bin nur verwirrt darüber, wie es aufgerufen werden würde, und warum dieser Ansatz anstelle einer generischen Setter-Methode verwendet würde.

Antwort

24

Dies wäre, wenn Sie eine Eigenschaft haben, die Sie nicht möchten, dass jemand außer Ihrer Klasse setzt. Dies kann bei Datenbank-IDs hilfreich sein. Die interne Klasse kann es einstellen, aber Sie möchten nicht, dass jemand anderes es ändert. So können Sie ihnen Lesezugriff geben, aber nicht schreiben.

EDIT: Ein weiterer Punkt hier ist, dass die Verwendung, was Sie dort gezeigt haben, für automatische Eigenschaften hilfreich ist. Leider können Sie mit den automatischen Eigenschaften nicht nur get angeben, um zu vermeiden, dass ein Setter öffentlich verfügbar gemacht wird.

EDIT: Ich dachte nur, ich würde ein Beispiel einwerfen. Automatische Eigenschaften sind ideal für sauberen, knappen Code. Aber wie Sie gezeigt haben, gibt es eine Einschränkung darin, dass Sie haben und setzen müssen. Also, bevor es so für eine Eigenschaft war wie Sie zeigte:

public class Test 
{ 
    private object thingy; 
    public object Thingy 
    { 
     get { return thingy; } 
    } 
} 

Jetzt können wir dieses nicht benötigten privaten Erklärung loszuwerden, aber es erfordert beides. Also mach dich privat, um das zu umgehen.

Ich weiß, das war Overkill auf die Erklärung, aber verschiedene Dinge poppten in meinem Kopf.

+1

Ah, ich wusste nicht, dass sowohl get und set für Auto-Eigenschaften deklariert werden musste. Das macht viel mehr Sinn. –

4

Der private macht es in eine readonly Eigenschaft. Ein allgemeines Beispiel ist, wenn Sie mehrere Klassen haben, die um ein einzelnes Objekt herumlaufen, wollen Sie nicht, dass eine andere Klasse die Instanz ändern kann.

9

Als ein einfaches Beispiel; es ist eine billige Möglichkeit, ein "unveränderliches" Objekt zu erstellen (für Threading, State, etc.). Aber auch überall wo der Client einfach nicht zuordnen muss, oder kann nicht vertraut werden um es zuzuordnen (richtig).

Ein weiteres Beispiel könnte eine Liste sein:

public List<Foo> Items {get;private set;} 

da wir obj.Items.Add() etc nennen könnte, aber wir würden selten obj.Items = ... zuweisen. Jedoch ist dieses Beispiel durch, um explizite Initialisierung im Konstruktor getrübt, und XmlSerializer hasst es - für Listen ehrlich zu sein, habe ich hauptsächlich verwenden:

private readonly List<Foo> items = new List<Foo>(); 
public List<Foo> Items {get { return items;}} 

, die beide diese lösen.

Als ein anderes Beispiel kontras:

private readonly int foo; 
public int Foo {get{return foo;}} 

vs

private readonly int foo; 
public int Foo {get{return foo;} private set {foo=value;}} 

Dieses Muster kann wird in der Serialisierung, beispielsweise mit DataContractSerializer (mit dem Zusatz von einigen Attributen), da viele Serialisierer nützlich sein, suche immer noch nach privaten Accessoren. Dies vermeidet, dass wir unseren internen Zustand (foo) dekorieren müssen, aber gibt die Furnier der Privatsphäre an die set.

Letztlich alles Bypässe sein kann und über Reflexion zugeordnet, so privat set nur versehentliche Beschädigung von Daten vermeiden soll.

+0

Ihre Punkte über die Liste und den Serializer sind gut gemacht. Dank dafür. :-) –

+0

+1! Obwohl ich generische ReadOnlyCollection oder Collection statt List offen legen würde - siehe http://blogs.msdn.com/b/codeanalysis/archive/2006/04/27/585476.aspx – TrueWill

2

Grundsätzlich handelt es sich um eine schreibgeschützte Eigenschaft. Wenn es vollständig geschrieben wurde (nicht als eine automatische Eigenschaft), würden Sie den Setter einfach weglassen.

Zwei Beispiele, die weitgehend die gleichen sind:

class Foo1 
{ 
    public int Id { get; private set; } 
    public Foo1() 
    { 
     Id = lastId ++; 
    } 
} 

class Foo2 
{ 
    private int _id; // could be readonly 
    public int Id { get { return _id; } } 
    public Foo2() 
    { 
     _id = lastId ++; 
    } 
} 
1

Diese Syntax ermöglicht es Ihnen, eine öffentlich zugängliche Eigenschaft zu schaffen, die für die Verbraucher von Ihrer API-nur lesen scheint aber intern zu ändern ist. Durch die automatische Implementierung auf diese Weise vermeiden Sie, dass Sie einen Standardcode wie einen eindeutigen Setter oder ein Hintergrundfeld für den Wert schreiben müssen, und Sie lassen in Ihrem Entwurf Platz, um einen Algorithmus für einen benutzerdefinierten Satz hinzuzufügen, wenn dies zu einem bestimmten Zeitpunkt in erforderlich erscheint die Zukunft, ohne sich gleich entscheiden zu müssen.

0

Dies ist nur laziness, die von Auto-Eigenschaften kommt. Bevor die automatischen Eigenschaften verfügbar waren, wurde der Getter implementiert und der Setter für Eigenschaften, die schreibgeschützt sein sollten, weggelassen.

public class Test 
{ 
    private /*readonly*/ Type _thingy; 
    public Type Thingy { get { return _thingy; } } 
} 

Hoffentlich C# 5 können Sie Auto-Eigenschaften mit einem Getter nur schaffen - denn das ist es, was jeder will. (Sie sollten lesen Sie nur Setters in Auto-Requisiten auch, ich brauche das schlecht)

+0

, wenn die Absicht ist, "readonly" einzuführen, dann gut; aber als allgemeiner "nur veränderlich * intern *" (was ein allgemeines Bedürfnis ist) würde ich nicht zustimmen können; Es hat wenig Vorteile, in diesem Fall ein explizites Feld zu haben. –

+0

Ja, die Einführung von Readonly ist, was ich meinte. Ich möchte nur eine Syntaxreduktion sagen "int Thingy {get; nur gelesen = 100; } 'oder so ähnlich. –

1

Private Set ist sehr praktisch für einfache unveränderliche Werttypen.

struct Point 
{ 
    public int X { get; private set; } 
    public int Y { get; private set; } 
    public Point(int x, int y) 
    { 
     this = default(Point); 
     X = x; 
     Y = y; 
    } 
} 
+0

Ich denke, Sie können ': this()' zur Konstruktordeklaration hinzufügen, anstatt 'this = default (Point)'? –

2

Ich habe dies mit dem Design verwendet gesehen:

public class whatever 
{ 
    public string WhateverId { get; private set; } 

    public static whatever Create(string whateverId) 
    { 
     return new whatever() { WhateverId = whateverId }; 
    } 
} 

So erstellen Sie unabhängig von Klasse, aber nachdem es die ID erstellt wird kann nicht geändert werden, weil es Dinge brechen könnte, die verbunden sind, es.

der private Satz gibt nur die einfache Initialisierungssyntax, ich mag es für einige Szenarien.

kann auch verwendet werden, wenn es wechselhaft ist, aber Sie müssen es verwalten, wenn Änderungen vorgenommen werden

public void SetWhateverId(string whateverId) 
{ 
    DisconnectAllCurrentWhateverIdReferences(); 
    WhateverId = whateverId; 
    ReconnectAllPreviousWhateverIdReferences(); 
} 
0

Um die Frage eines gemeinsamen Szenario zu beantworten, wo diese verwendet werden könnten ... In einem MVP-Muster, wenn Ihr Modell einige Eigenschaften für Ihre Presenter aussetzt würde ich schreiben

public string Bazinga { get; private set; } 

Nun kann das Modell diesen Wert ändern, sondern auch andere Klassen, die es verwenden, kann es nicht.