Reputation: 7446
I've been looking around, and so far haven't managed to find a good way to do this. It's a common problem, I'm sure.
Suppose I have the following:
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 */
}
The idea being, I'm going to implement a binary heap, and rather than only support Insert() and DeleteMin() operations, I want to support "peeking" at the highest (or lowest, as the case may be) priority value on the stack. Never did like Heisenberg, and that whole "you can't look at things without changing them" Uncertainty Principle. Rubbish!
The problem, clearly, is that the above provides no means to prevent calling code from modifying MyVal (assuming SortedCollection) via the Top property, which operation has the distinct possibility of putting my heap in the wrong order. Is there any way to prevent modifications from being applied to the internal elements of the heap via the Top property? Or do I just use the code with a warning: "Only stable if you don't modify any instances between the time they're inserted and dequeue'd. YMMV."
Upvotes: 1
Views: 221
Reputation: 23941
I understand your problem now. I think this should work:
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 */
}
The ICloneable constraint ensures that the type parameter implements the ICloneable interface. (if this is acceptable)
Upvotes: 0
Reputation: 55730
To answer your question: No, there's no way to implement the kind of behavior you want - as long as T is of reference type (and possibly even with some value-types)
You can't really do much about it. As long as you provide a getter, calling code can modify the internal contents of your data depending on the accessibility of said data (i.e. on properties, fields, and methods).
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
NOTE What I mean is you can't really prevent it in the case of classes that you don't control. In the example, like others have stated you can make MyVal's set private or omit it; but since SortedColleciton is a generic class, you can't do anything about other people's structures..
Upvotes: 1
Reputation: 99889
Your properties don't have to have the same accessibility for get
/set
. This covers you for anything that returns a value type (typically struct
s that only contain value types) or immutable reference types.
public int MyVal
{
get { return myVal; }
private set { myVal = value; }
}
For mutable reference types, you have other options, such as returning Clone()
s or using ReadOnlyCollection<T>
to keep the caller from changing them:
private List<int> data;
public IList<int> Data
{
get { return new ReadOnlyCollection<int>(this.data); }
}
Upvotes: 1
Reputation: 2915
Only implement getters for your properties and modify the collection by having add/remove methods
Upvotes: 0
Reputation: 415901
You can have a readonly property (that is, a property with only a getter):
private int myVal;
public int MyVal { get { return myVal; } }
But be careful: this may not always work how you expect. Consider:
private List<int> myVals;
public List<int> MyVals { get { return myVals; } }
In this case, you can't change which List the class uses, but you can still call that List's .Add()
, .Remove()
, etc methods.
Upvotes: 1