2009-07-20 3 views
1

Ich habe mich umgesehen, und bis jetzt ist es nicht gelungen, einen guten Weg zu finden, dies zu tun. Es ist ein häufiges Problem, da bin ich mir sicher.Enthält C#/CLR einen Mechanismus zum Kennzeichnen der Rückgabewerte von Eigenschaften als schreibgeschützt/unveränderlich?

Angenommen, ich habe folgendes:

class SomeClass : IComparable 
{ 
    private int myVal; 
    public int MyVal 
    { 
     get { return myVal; } 
     set { myVal = value; } 
    } 

    public int CompareTo(object other) { /* implementation here */ } 
} 

class SortedCollection<T> 
{ 
    private T[] data; 
    public T Top { get { return data[0]; } } 

    /* rest of implementation here */ 
} 

Die Idee dahinter ist, werde ich einen binären Heap implementieren, und anstatt nur unterstützen Insert() und deletemin() -Operationen, ich will "unterstützen spähen "auf den höchsten (oder niedrigsten, je nachdem) Prioritätswert auf dem Stapel. Nie wie Heisenberg, und das ganze "Du kannst die Dinge nicht ansehen, ohne sie zu verändern". Unschärferelation. Müll! Das Problem besteht klar darin, dass das obige keine Möglichkeit bietet, zu verhindern, dass der Aufrufcode MyVal (unter der Annahme von SortedCollection) über die Top-Eigenschaft ändert, wobei diese Operation die eindeutige Möglichkeit hat, meinen Heap in die falsche Reihenfolge zu setzen. Gibt es eine Möglichkeit zu verhindern, dass Änderungen über die Eigenschaft Top auf die internen Elemente des Heapspeichers angewendet werden? Oder verwende ich den Code nur mit einer Warnung: "Nur stabil, wenn Sie keine Instanzen zwischen dem Zeitpunkt, an dem sie eingefügt und aus der Warteschlange entfernt werden, ändern. YMMV."

+0

Sie könnten eine unveränderbare Prioritätswarteschlange implementieren. Jede Warteschlange ist unveränderlich; Hinzufügen oder Entfernen eines Elements gibt eine völlig neue Warteschlange zurück. Ich habe C# Quellcode für so etwas irgendwo herum; Ich werde sehen, ob ich es ausgraben kann. –

+0

Hrm ... Ich mag die Idee, aber ich glaube nicht, dass es letztendlich das Problem löst, denn das Problem, das ich betrachte, ist in Bezug auf die Ungültigkeit der Bestellung aufgrund der Änderung eines vorhandenen Elements, anstatt die Einfügung/Löschvorgänge. – Dathan

Antwort

1

Um Ihre Frage zu beantworten: Keine, gibt es keine Möglichkeit, das gewünschte Verhalten zu implementieren - solange T vom Referenztyp ist (und möglicherweise sogar mit einigen Werttypen)

Sie können wirklich nicht viel dagegen tun. Solange Sie einen Getter bereitstellen, kann der Aufrufcode den internen Inhalt Ihrer Daten abhängig von der Zugänglichkeit dieser Daten (d. H. Eigenschaften, Felder und Methoden) ändern.

class SomeClass : IComparable 
{ 
    private int myVal; 
    public int MyVal 
    { 
     get { return myVal; } 
     set { myVal = value; } 
    } 

    public int CompareTo(object other) { /* implementation here */ } 
} 


class SortedCollection<T> 
{ 
    private T[] data; 
    public T Top { get { return data[0]; } } 

    /* rest of implementation here */ 
} 

//.. 
// calling code 
SortedCollection<SomeClass> col; 
col.Top.MyVal = 500; // you can't really prevent this 

HINWEIS Was ich meine ist, dass Sie nicht wirklich im Fall von Klassen verhindern können, dass Sie nicht kontrollieren.In dem Beispiel, wie andere angegeben haben, können Sie das MyVal-Set privat machen oder es weglassen; aber da SortedColleciton eine generische Klasse, können Sie nichts tun, über andere Menschen Strukturen ..

+0

Sie treffen den Nagel direkt auf den Kopf - danke. Was ich in diesem Fall in Erwägung ziehe, ist ein bisschen weiter zu gehen und etwas wie Castle DynamicProxy zu verwenden, um einen Wrapper um den sortierten Typ zu erstellen und diesen Wrapper als Top-Element zurückzugeben. Es wirft einige Probleme auf, könnte aber in einigen Fällen funktionieren. Ich werde wahrscheinlich auch die Unterstützung für das Abfangen von INotifyPropertyChanged-Ereignissen implementieren, wenn der Typ dies unterstützt und ggf. den Heapspeicher umleitet und die an anderer Stelle beschriebene ICloneable-Lösung unterstützt. Das sollte eine große Anzahl von Fällen erfassen. Und wenn nicht, habe ich es zumindest versucht. – Dathan

1

Sie können eine Nur-Lese-Eigenschaft haben (das heißt, eine Eigenschaft mit nur einem Getter):

private int myVal; 
public int MyVal { get { return myVal; } } 

Aber Vorsicht: dies nicht immer funktionieren, wie Sie es erwarten. Bedenken Sie:

private List<int> myVals; 
public List<int> MyVals { get { return myVals; } } 

In diesem Fall können Sie nicht, die die Klasse Liste ändern verwendet, aber Sie können anrufen trotzdem auf die .Add() Liste, .Remove(), etc Methoden.

+0

In diesem Fall kann ich je nach Situation eine ReadOnlyCollection zurückgeben. +1 –

+0

Obwohl das ist etwas neben dem Sinn dieses Threads/Antwort. –

0

Nur Getter für Ihre Eigenschaften implementieren und die Sammlung ändern, indem Methoden

1

Ihre Eigenschaften müssen nicht die gleiche Zugänglichkeit für get/set haben entfernen hinzufügen/aufweisen. Dies deckt Sie für alles ab, was einen Werttyp (normalerweise struct s, die nur Werttypen enthalten) oder unveränderliche Referenztypen zurückgibt.

public int MyVal 
{ 
    get { return myVal; } 
    private set { myVal = value; } 
} 

Für änderbare Referenztypen, Sie haben andere Möglichkeiten, wie zum Beispiel der Rückkehr Clone() s oder mit ReadOnlyCollection<T> die Anrufer zu verhindern, sich zu ändern:

private List<int> data; 

public IList<int> Data 
{ 
    get { return new ReadOnlyCollection<int>(this.data); } 
} 
+0

FYI - Der C# -Compiler unterstützt ein wenig syntaktischen Zucker für schreibgeschützte Auto-Eigenschaften: public int MyVal {get; privates Set; }. Dies kann Ihre Eigenschaftsdeklarationen etwas sauberer machen, wenn Sie mehrere dieser Eigenschaften in einem einzigen Typ haben. – Levi

+0

Ich mag die Klon-Idee ... Ich möchte die Sammlung nicht darauf beschränken, nur Cloneable-Datentypen zu unterstützen, aber in dem Fall, dass der Typ IS geklont werden kann, kann die Unterstützung dieser Art von Verhalten meine Ängste beruhigen. Vielen Dank! – Dathan

+0

@Levi Danke für die Info. Ich habe diesen Code jedoch in ein VS 2005-Projekt aufgenommen. Mein Verständnis ist, dass Auto-Eigenschaften ab 2008 unterstützt werden. – Dathan

0

ich Ihr Problem verstehen jetzt. Ich denke, das sollte funktionieren:

class SortedCollection<T> where T: ICloneable 
{ 
    private T[] data; 
    public T Top 
    { 
     get 
     { 
      T ret = (T)data[0].Clone(); 
      return ret; 
     } 
    } 

    /* rest of implementation here */ 
} 

Die ICloneable-Einschränkung stellt sicher, dass der Typparameter die ICloneable-Schnittstelle implementiert. (Wenn dies akzeptabel ist)

Verwandte Themen