Sign in to follow this  
bluntman

[.net] Read only properties.

Recommended Posts

bluntman    255
I just wrote this as a test, because I wanted to know how the properties access works, and it has confused me...
    class SubFool
    {
        public int S;
    };

    class Fool
    {
        private SubFool f;

        public Fool()
        {
            f = new SubFool();
        }

        public SubFool F
        {
            get { return f; }
        }
    };

    class Program
    {
        static void Main(string[] args)
        {
            Fool F = new Fool();

            F.F.S = 10;

            Console.WriteLine("F.F.S = {0}", F.F.S);
            Console.ReadKey();
        }
    }

This compiles, and the output is "F.F.S = 10", my question is: Why am I allowed to change members of a readonly property? How do I make this property _really_ readonly? Thanks!

Share this post


Link to post
Share on other sites
Machaira    1033
The property is truly readonly. You can't do:

F.F = new SubFool();

Note the error you get if you try. What exactly do you want to do? You could do:

public SubFool F
{
get { return new SubFool(); }
}


but is that what you're trying to do?

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
What about ...


class Inner
{
public int Data;

public Inner()
{
Data = 7;
}

public Inner(Inner param)
{
Data = param.Data;
}
}

class Outer
{
private Inner member;
public Inner Member
{
get { return new Inner(member); }
}

public Outer()
{
member = new Inner();
}
}

class Program
{

static void Main(string[] args)
{
Outer o = new Outer();
o.Member.Data = 3;

Console.WriteLine("Outer.Member.Data = {0}", o.Member.Data);
Console.ReadKey();
}
}

Share this post


Link to post
Share on other sites
davepermen    1047
he expected to have S in SubFool to be readonly, too, because the property is readonly. but this is not true. the object returned from the readonly property is NOT readonly, you have full access to it.

i'd like to know a way to make the whole SubFool readable then, too. always nice to know such stuff :D

Share this post


Link to post
Share on other sites
kanato    568
If you make SubFool a struct instead of a class, a copy of it will be returned instead when calling F.F. So the actual SubFool object stored in F cannot be modified.

Using a struct instead of a class has other implications too, so you should be aware of those if you make that change...

Share this post


Link to post
Share on other sites
davepermen    1047
but none of those generates a compile time error when assigning something to the sub item of the readonly property, thus making it clear that you cannot manipulate it.

all those tricks hide the fact that it's non-modifiable, which is a bad thing.

Share this post


Link to post
Share on other sites
kanato    568
You'll get a compile time error if the SubFool class is a struct.

People often ask the question about this type of error if they try to do something like MyForm.Location.X = 40; this generates a compile time error because the compiler is smart enough to not let you assign a value to a temporary struct returned from a property or method.

Share this post


Link to post
Share on other sites
Dorvo    272
bluntman,

You can make any property truly read only by declaring the internal variable for that property "readonly".


class SubFool
{
public int S = 9;
};

class Fool
{
private readonly SubFool f;

public Fool()
{
f = new SubFool();
}

public SubFool F
{
get { return f; }
}
};

class Program
{
static void Main(string[] args)
{
Fool F = new Fool();

F.F.S = 10;

Console.WriteLine("F.F.S = {0}", F.F.S);
Console.ReadKey();
}
}




Now, your SubFool instance inside Fool will stay the same no matter what you try to do to it through the property. The compiler will actually yell at you and tell you that it cannot be assigned to because it's readonly.

Hope that helps.

Share this post


Link to post
Share on other sites
Niksan    127
As already mentioned you can mark the element within SubFool as readonly, a lot of the winforms rectangles and the like do the same thing so if you want to change any component you have to assign a new rectangle each time, however, IIRC using the readonly flag means you can only set the variable in the constructor, so it probably depends on the implimentation, whether a constant would suffice instead.

Basically your code is doing the following.

F.F.S = 10 is valid because it's only reading the F class you marked read only.

If you try F.F = new SubFool it won't compile, because it's readonly.

Share this post


Link to post
Share on other sites
bluntman    255
Thanks for the help.
Dorvo, I tried the readonly keyword and it makes no difference, I am still allowed to assign to F.F.S!
I guess it makes sense how it is tho, as the property is just the reference to the object in memory and I am not allowed to change that. But that still makes it seem a bit C++ish.
The context of this problem for me is this:
I am writing a small scene graph and in my Transform node type there is a Matrix property which I want to be read only, and only modifiable via seperate Rotation, Scale and Translation properties.

Share this post


Link to post
Share on other sites
Niksan    127
Quote:
Original post by bluntman
Thanks for the help.
Dorvo, I tried the readonly keyword and it makes no difference, I am still allowed to assign to F.F.S!


You're talking about readonly on F rather than S within the SubFool class, which I assume Dorvo was talking about.

EDIT: If you're using value type matrix it shouldn't matter as you'd essentially be returning a copy.

[Edited by - Niksan on November 28, 2006 5:55:52 AM]

Share this post


Link to post
Share on other sites
bluntman    255
What I basically want to do is what would in C++ look like:


class SubFool
{
public:
int S;
};

class Fool
{
private:
SubFool *F;
public:
const SubFool *getSubFool()
{
return const_cast<const SubFool*>(F);
}
};

main()
{
Fool f;
f.getSubFool()->S = 10; // compile time error!!!
}


Share this post


Link to post
Share on other sites
Skizz    794
This nearly does what you want. It only fails if the SubFool object isn't created by the Fool object, i.e. it's not a FoolSubFool object pretending to be a SubFool object.

public class SubFool
{
protected int m_s;

public int S
{
get { return m_s; }
}
}

class Fool
{
// a private member class derived from read only class
class FoolSubFool : SubFool
{
public new int S
{
set { m_s = value; }
get { return m_s; }
}
}

FoolSubFool f;

public SubFool F
{
get { return f; } // return the read only version
}

public Fool ()
{
f = new FoolSubFool ();
f.S = 9; // can assign to it
int s = f.S; // can read from it
}
}

class Program
{

static void Main (string [] args)
{
Fool f = new Fool ();
//f.F.S = 3; // this doesn't work - compile error

Console.WriteLine ("f.F.S = {0}", f.F.S); // this is ok
Console.ReadKey ();
}
}





Skizz

Share this post


Link to post
Share on other sites
VizOne    598
The essential thing that is missed here is: readonly != constant. There is no direct equivalent to a C++ Method returning a "const &" or similar in C#.

See here (section "Immutables") for an explanation from the creators of C#.

Regards,
Andre

Share this post


Link to post
Share on other sites
Dorvo    272
bluntman,

Why prevent the user from being able to directly change the matrix? Wouldn't that impair some functionality of your Transform node?

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this