16 October 2007

C# 3.0 Automatic Properties - Incomplete Feature?

Well, C# 3.0 is nice language. However, digging into details of every new language feature while developing ReSharper support make me wonder about little things that look like incompleteness. Today I'm going to wonder about automatic properties.

public string Name { get; set; }

This code is correct in C# 3.0, there are no missing "abstract" or get/set bodies. It simply means that compiler will create field and accessors code for you:

private string __someGeneratedFieldName;
 
public string Name
{
  get { return __someGeneratedFieldName; }
  set { __someGeneratedFieldName = value; }
}


What is cool about automatic properties? Obviously, ReSharper users don't benefit much from shorter code - who types properties by hand these days? However there is one very important thing:

Less complexity to manage.

If you want to know how this property gets its value, you no longer need to search for both field and property usages. You don't need to synchronize field and property types, once you decide to change it. Also, access to the class attribute (in OOP sense) is fully controlled right at the place of the declaration. You can limit it as you wish:

public string Name { get; private set; }

This way you declare that "Name" can be modified only within the class itself, but can be read from outside.

So, what is missing from this language feature?

Initializer.
I may wish to initilize property to some non-default value. Like this:

public List<Person> Persons { get; private set; } = new List<Person>();

Read-only automatic property
In the example above, I don't actually need setter.

public List<Person> Persons { get; } = new List<Person>();

Obviously, you don't need read-only automatic property without initializer. Also note, that such property can never change its value, even in constructor, unlike readonly fields.

Attributes on generated fields
If you use simple event form and compiler generates field for storing delegate, you can apply attribute to the generated field by using attribute target:

[field: NonSerialized]
public event EventHandler Closed;

I wish I could do the same with automatic properties:

[field: NonSerialized]
public List<Person> Persons { get; } = new List<Person>();


Conclusion
Few simple improvements over existing implementation could make automatic properties much more useful in everyday professional .NET development. Unfortunately, language designers decided:
they would work in the "common case" which among other things means no attributes on the generated field. The idea behind that is keeping them simple and not slowly mutating them into full properties.

I'd prefer the advanced version, if I had a chance to choose.

8 comments:

Phil Scott said...

I can probably see myself starting out with auto properties. What would be nice is if resharper could "expand" these out to full properties when the time comes.

Ilya Ryzhenkov said...

Of course, ReSharper 4.0 will support that kind of property expansion. It will also provide suggestion to convert existing properties to auto-properties if they already used in that flavour. Other properties also can be converted if they meet certain criteria, via context action.

Fabian said...

Have you opened a Connect issue for the [field:NonSerialized] thing as Marcelo suggested on the forum? I'd vote for it...

You could also include the initializer and read-only property suggestions, although they'll most definitely be rejected as "by design", at least for C# 3.0.

Ilya Ryzhenkov said...

No, I didn't open it. I simply don't think it worth the effort of loggin in :) It is obviously not going to be in VS2008 and we probably have another 2 or 3 years before next update of language (if any). Then, in 2010, I think we will have pretty different feeling about the language and the features.

nikov said...

What about a Quick Fix in ReSharper which would convert currently illegal code like:

[field: NonSerialized]
public List < Person > Persons { get; } = new List < Person > ();

into full property with a backing field?

Ilya Ryzhenkov said...

Vladimir,

I don't think we can do this. It would pollute parser unnecessary, add complexity to all the code to deal with such constructs, with the only reason to allow quick fix. May be, we'd better write own language? :)

Eric Hauser said...

If you want to initialize a default value, you can just use the constructor. Not tool friendly, but not necessary an incomplete feature.

Frank said...

Another nice thing that Microsoft *could* have done, would be to generate a 'Changed' event for auto-generated properties.

That would eliminate 90% of my reasons to write a custom setter, since I could then handle the synchronization and updates via the event / delegate.

My $0.02

If ReSharper 4.0 could somehow allow you to 'add a changed event' to a property that would be just as good. Not sure how you'd go about that, but it would be a cool feature.