Automatic properties are supported by C# since version 3.0 and as developers we use them almost every day. Sometimes developers have questions about how automatic properties work and how to effectively use them. Also I bust some myths about automatic properties and go deep with internals.
What is automatic property?
Automatic property in C# is a property that has backing field generated by compiler. It saves developers from writing primitive getters and setters that just return value of backing field or assign to it.
Instead of writing property like this:
public class Dummy
{
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
}
we can write it like this as there is no additional logic involved in getter and setter:
public class Dummy
{
public string Name { get; set; }
}
We can use attributes in many cases but often we need properties because features in different .NET technologies expect properties instead of attributes (example: data binding in ASP.NET Forms and model binding in ASP.NET MVC).
Automatic property after compiling
I said that automatic property is practically a synonym for regular property. Let’s see what compiler produces of automatic property.
public class Dummy
{
[CompilerGenerated]
private string <Name>k__BackingField;
public string Name
{
[CompilerGenerated]
get { return <Name>k__BackingField; }
[CompilerGenerated]
set { <Name>k__BackingField = value; }
}
}
The only difference from regular property is using of CompilerGenerated attribute. This attribute tells development tools which elements of application code are generated by compiler. Don’t confuse it with GeneratedCode attribute that is applied to code generated by coding tools.
This is how development tools must understand automatic property shown above:
- backing field property is decorated with CompilerGenerated attribute – don’t show it to users,
- property Name must be visible for users,
- body of get and set accessors is generated by compiler – don’t show body but show that get and set are available.
As a developers we usually don’t have to care much about differences between automatic and regular property and we are free to go with the one that results in more readable code.
Read-only automatic properties
Sometimes we need to do ugly tricks when property is expected although we would like to go with public constant perhaps. Remember data and model binding mentioned before. Since C# 6.0 we can use automatic property initializers so we can directly assign initial value to automatic property.
public class Dummy
{
public const string OfficialName = "The Very Big Corporation";
public string CompanyName { get; } = OfficialName;
}
It seems clean and beautiful but it is actually an illusion. After building code in release mode, removing program debug database and opening resulting library with decompiler we can see a little bit different code.
public class Dummy
{
public const string OfficialName = "The Very Big Corporation";
[CompilerGenerated]
private string <CompanyName>k__BackingField;
public string Name
{
[CompilerGenerated]
get { return <CompanyName>k__BackingField; }
}
public Dummy()
{
<CompanyName>k__BackingField = "The Very Big Corporation";
}
}
Assigning value to backing field in class constructor is effective way to get around the need for setter where assignment should usually happen.
Assigning values to backing fields
Now we can ask if compiler created code can assign value to backing field then why cannot our code do it? We can do it using reflection and by writing some helper methods. As this is not the way to go I just give a short advice here and pray that code like this doesn’t get to my table.
ATTENTION! It is not recommended practice to break into classes and modify their private fields directly. Before doing something like this please try to find some other way. Getting into private scope of class is last option and using this must be very well considered decision.
One possible scenario is assigning expected state to object when unit testing them. The goal is to set class to expected state directly without accidentally calling setters that may start the chain of events that are not necessary in context of testing. If source code of classes is not under your own control you may consider this option. But again – please try everything else before going with this approach.
One idea is to use BackingFieldResolver by Jb Evain to find backing field for automatic property. To get BackingFieldResolver just add Mono.Reflection NuGet package to your solution. I modified Dummy class for this example and added regular property for company registration number. There is also property that doesn’t assign to any backing field.
public class Dummy
{
public const string OfficialName = "The Very Big Corporation";
public string CompanyName { get; } = OfficialName;
private string _regCode;
public string RegCode
{
get { return _regCode; }
set { _regCode = value; }
}
public string DisplayName
{
get { return CompanyName + ": " + _regCode; }
set { }
}
}
Let’s find out bacing field names using Mono.Reflection library.
class Program
{
static void Main(string[] args)
{
var field1 = typeof(Dummy)
.GetProperty(nameof(Dummy.CompanyName))
.GetBackingField();
var field2 = typeof(Dummy)
.GetProperty(nameof(Dummy.RegCode))
.GetBackingField();
var field3 = typeof(Dummy)
.GetProperty(nameof(Dummy.DisplayName))
.GetBackingField();
Console.WriteLine(field1.Name);
Console.WriteLine(field2.Name);
}
}
When running this code we will see the following output on screen for first two fields (comment third one out):
<CompanyName>k__BackingField _regCode
Third field gives us ArgumentException because it was not possible to find backing field for DisplayName property.
Assigning value to backing field is simple.
static void Main(string[] args)
{
var field1 = typeof(Dummy)
.GetProperty(nameof(Dummy.CompanyName))
.GetBackingField();
var dummy = new Dummy();
field1.SetValue(dummy, "Small NGO");
Console.WriteLine(dummy.CompanyName);
}
When running this code we get Small NGO as output.
Myths around automatic properties
Like every automagic thing in technology also automatic property is not free of myths.
- Automatic property is more effective than regular one. They are practically same thing. Backing field of automatic property is generated by compiler and backing field of regular property is written by developer manually. Testing which one is faster is tricky as testers must know if method inlining and other runtime optimizations are equally used on properties they compare.
- Backing field of automatic property raises compiler overhead. It’s actually not a myth but considering how powerful are even simple laptops today I don’t see that using automatic properties put any markable overhead to compiler. We loose probably few milliseconds and so what?
- Automatic property is anti-pattern. I have heard the statement but never valid proof for it. As shown above technically is automatic property practically the same as regular property. It is going through same optimizations as regular property. The only difference is that backing field is automatically generated.
- Backing fields doesn’t support attributes. There are rare cases when attributes on backing field are needed but this problem is solved with C# 7.3, see my blog post Adding attribute to backing field of automated property. You can define attribute that targets fields and apply it to backing field of automated property by decorating it by your custom attribute using syntax like this: [field: MyCustomAttribute].
Wrapping up
From developer perspective automatic and regular properties are equal. Automatic properties have automatically generated backing field and smaller syntax. But on all other means it is equals to regular property. In rare and extreme cases we may need to assign values to backing fields of automatic properties and this is possible through reflection although it is not recommended way to do things. Finally there are different myths about automatic properties but they don’t hold true and before falling with these consipracy theories I suggest to try thinsg out by yourself before doing some bad mistake. If you still have a question if you should use automatic properties or avoid them, the answer is simple –automatic properties are safe to use and go with them if they help you.
View Comments (3)
Why not just make the data member public with a capitalized name (ala property syntax)? Then if you wanted to add behavior, you can add formal property syntax and change the data member to be private with a lower case name. Same diff: you don't break clients that use property syntax.
Cool article as for me. I'd like to read more concerning that topic.
@George that is a breaking change at the binary level. Code which consumes the field would need to be recompiled to consume the property, even though it has the same name.