poke
poke

Reputation: 387507

Disallow setting property's property

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

Answers (5)

Thomas Levesque
Thomas Levesque

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 compile time, because the compiler doesn't know that it would modify a copy (again, unless it's a struct)
  • 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

Esteban Araya
Esteban Araya

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

TheFogger
TheFogger

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

CodeNaked
CodeNaked

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

C.J.
C.J.

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

Related Questions