Question

I frequently find myself wanting to do something along these lines:

Form form = new Form();
form.ClientSize.Width = 500;

Of course the compiler will now complain that this code is not valid, since ClientSize is a property, and not a variable.

We can fix this by setting the ClientSize in its entirety:

form.ClientSize = new Size(500, ClientSize.Height);

Or, in general:

Size s = form.ClientSize;
s.Width = 500;
form.ClientSize = s; //only necessary if s is a value-type. (Right?)

But this is all looks unnecessary and obfuscated. Why can't the compiler do this for me? And of course, I'm asking about the general case, possibly involving even deeper levels of properties, not just the mundane example above

Basically, I'm asking why there is no syntactic sugar to translate the line form.ClientSize.Width = 500 into the above code. Is this simply a feature which hasn't yet been implemented, is it to avoid stacking of side effects from different getters and setters, to prevent confusion when one of the setters isn't defined, or is there a completely different reason why something like this doesn't exist?

Was it helpful?

Solution 3

For the compiler to allow myForm.ClientSize.Width = 500;, one of two things would be necessary: either the compiler would have to assume that the intended behavior is equivalent to:

var temp = myForm.ClientSize;
temp.Width = 500;
myForm.ClientSize = temp;

or else myForm would have to associate the name ClientSize with a method whose signature was:

void actupon_ClientSize<TParam>(ref Rectangle it, ref TParam param);

in which case the compiler could generate code similar to

myForm.actupon_ClientSize<int>((ref Rectangle r, ref int dummy)=>r.Width = 500, ref someDummyIntvar);

where someDummyIntVar would be an arbitrary value of type int [the second ref parameter would make it possible to pass parameters to the lambda without generating a closure]. If the Framework described a standard way for objects to properties to be exposed like that, it would make many types of programming safer and more convenient. Unfortunately, no such feature exists nor do I expect any future version of .NET to include it.

With regard to the first transformation, there are many cases where it would yield the desired effect, but also many where it would be unsafe. IMHO, there is no good reason why .NET shouldn't specify attributes which would indicate when various transformations are and are not safe, but they need for them has existed since Day One, and since the programmers responsible for .NET have consistently decided that they'd rather declare mutable structures to be "evil" than do anything that would make them be not evil, I doubt that will ever change either.

OTHER TIPS

Why can't the compiler do this for me?

It can. In fact, if you were programming in VB it would do exactly that. The C# compiler doesn't do this because it generally takes the philosophy of doing what you tell it to do; it is not a language that tries to guess at what you want to do and do that instead. If you tell it to do something silly, it'll just let you do something silly. Now this particular case is such a common source of bugs, and given these exact semantics is virtually certain to be a bug, so it does result in an error, because it's nice like that.

C# programmers learn to rely on the C# compiler never deciding to do something that you never told it to do, which can be a cause of confusion and problems when the compiler guess wrong about what you wanted to do.

I believe that you have a fundamental misunderstanding of .NET here. You can set properties of properties all day for class types because you're modifying the data of a reference without changing the reference. Take this code for example which compiles and runs fine:

class Program
{
    public class Complex1
    {
        public Complex2 Complex2Property { get; set; }
    }

    public class Complex2
    {
        public int IntProperty { get; set; }
    }

    static void Main( string[] args )
    {
        // You must create instances of all properties to avoid a NullReferenceException
        // prior to accessing said properties
        var complex1 = new Complex1();
        complex1.Complex2Property = new Complex2();

        // Set property of property
        complex1.Complex2Property.IntProperty = 7;
    }
}

I assume your object is a struct or value type. The reason you can't do this for structs is that a struct is a value type - it gets copied around by value, not reference. So if I changed the above example to make Complex2 a struct, I could not do this line:

complex1.Complex2Property.IntProperty = 7;

Because the property is syntactic sugar for a get method which would return the struct by value which means a copy of the struct, not the same struct that the property holds. This means my change to that copy would not affect the original property's struct at all, accomplishing nothing except modifying a copy of my data that isn't the data in my property.

As for why the compiler doesn't do this for you? it definitely could, but it won't because you'd never want to actually do this. There's no value in modifying a copy of an object that you don't actually reassign to your property. This situation is a common error for developers who don't understand value vs reference types entirely (myself included!) and so the compiler chooses to warn you of your mistake.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top