Reputation: 387507
I’m not sure what this is called, or where I did see this, so I don’t really know what to search for. Therefore I’m trying to explain what I mean.
Suppose I have the following class structure, where TypeB
is used within TypeA
:
class TypeA
{
public TypeB B
{ get; set }
}
class TypeB
{
public int X
{ get; set }
}
Now when I have an instance of TypeA, I want to disallow, that I can directly modify the values of TypeB without reassigning. So basically I want to prevent this:
TypeA a = new TypeA();
// this should not be possible:
a.B.X = 1234;
// but this should work:
TypeB b = a.B;
b.X = 1234;
a.B = b;
The reason is that I am persisting the object in a special way, so to keep track of changes in TypeB
correctly, I want to require that the value of B
within TypeA
is reassigned.
I think that I have seen a similar thing before with some built-in object, where this threw an error and compile time. What is this called, and how can I achieve it in my custom types?
Upvotes: 5
Views: 234
Reputation: 292345
You can return a copy of the TypeB
object from the property getter in TypeA
:
class TypeA
{
private TypeB _b;
public TypeB B
{
get { return (TypeB)_b.Clone(); }
set { _b = value; }
}
}
This will prevent modifying the properties of _b directly. However, it won't actually disallow to do a.B.X = 1234;
, but the instruction will have no effect (it will only modify a copy that will immediately be discarded).
Unless TypeB
is a struct, there is no way to prevent such an instruction:
it can't be detected at runtime either, because you can't tell the difference between:
TypeB b = a.B;
b.X = 1234;
and
a.B.X = 1234;
In both cases the property is called the same way, and there is no way to know what the calling code is doing with the result...
Upvotes: 3
Reputation: 29654
What if you made the property B in class A a readonly field? That way it could only set a construction and not changed afterwards.
Also, what about an internal/private setter? Does that fill the needs?
Upvotes: -2
Reputation: 2429
Have TypeB
implement an interface that defines X
with only a getter. Expose a property with this interface type on TypeA
. Now you can only modify the property's properties when you do a downcast, which is the most you can aim for.
This method will give you compile time safety. If you only need runtime safety, look at CodeNaked's answer.
Upvotes: 1
Reputation: 41393
In WPF/Silverlight there are two concepts of having "sealed" and "frozen" objects. Basically, once sealed/frozen, the object cannot be changed. You may be able to apply the same logic here:
public class SealableObject {
public bool IsSealed { get; private set; }
public void Seal() {
if (this.IsSealed)
throw new InvalidOperationException("The object is already sealed");
this.IsSealed = true;
}
protected void VerifyNotSealed() {
if (this.IsSealed)
throw new InvalidOperationException("Object is sealed");
}
}
Then you would need to check IsSealed
in your derived class TypeB
, like so:
class TypeB : SealableObject
{
private int x;
public int X
{
get { return this.x; }
set {
this.VerifyNotSealed();
this.x = value;
}
}
And then you'd need to seal TypeB when it is assigned to your TypeA property.
Upvotes: 3
Reputation: 16081
Your current code will not allow what you want. You cannot make int X read / write and only make it read only when B is stored in A. If you really want to keep the int X immutable, than don't keep it in type B. Instead keep the int value in A instead, and make it a read only value there.
Upvotes: 0