iTranslated by AI
[C#] Properties Revisited: More Than Just Getters and Setters

Introduction: Do you know about C# "Properties"?
Does everyone know what a C# "Property" is?
"I know!
You mean those getters/setters with the special syntax, right?"
...For those who answered that way.
This is **not wrong, but it's also wrong!!! (?)
The role of "Properties" in modern C# is broad and important
To be sure, in introductory C# articles, they are explained like this:
Properties are getters/setters that look like member variables from the outside.
— An introductory C# guide somewhere
As a functional explanation, it's not incorrect.
However, while this explanation isn't wrong, it is insufficient.

Properties in modern C# are
- much broader in usage
- much higher in importance
than the scope you would imagine from that explanation!!!
So, let's have a "Re-introduction" to the world of properties in modern C#.
When we talk about properties, we first mean auto-implemented properties
The declaration for a C# "property" uses this syntax:
public int IntProp { get; set; }
It's very simple.
It's almost no different from a "field" (what other languages call a member variable) except for adding { get; set; } at the end.
public int IntField;
Also, on the usage side, properties and fields are written exactly the same way.
class A{
public int IntProp { get; set; } // I'm a property!
public int IntField; // And I'm a field!
public void Clear()
{
// Access from within is the same
IntProp = default;
IntField = default;
}
}
// Access from outside is also the same
var a = new A();
a.IntProp = 123;
a.IntField = 456;
And if you use them like this, you don't really need to be conscious of getters/setters.
Because there are no getter/setter-like elements!
For normal use, it's enough to think of them as variables attached to a class or struct!
I'll write about the reasons in detail later, but in modern C#, properties are often "used as they are".
Official Recommendation: Use Properties instead of Fields for "Public" Members
There is an important point regarding the choice between properties and fields.
public int IntField;
The example I showed earlier, ↑ this ↑ (a public field). If the official Analyzer (= Linter) is enabled[1], you will be flagged.

CA1051: Do not declare visible instance fields (code analysis) - .NET | Microsoft Learn
The official recommendation is that anything that looks like a member variable and is visible from the outside should be a property.
- Reasons:
- The effort to write a property is the same as a field.
- Fields are weak against specification changes.
Simply put, fields are inconvenient and can be dangerous in some cases. In practice, properties are incredibly important in modern C#.
Properties are Resilient to Specification Changes
The statement "fields are weak against specification changes" means that properties are more resilient to specification changes compared to fields! After all, you can change the internal implementation without having to change the calling side!
class A{
int _intProp;
public int IntProp
{
get => _intProp;
set
{
// Due to a specification change, we now record double the value!
_intProp = value * 2;
}
}
}
var a = new A();
// No change needed here
a.IntProp = 123;
Console.WriteLine(a.IntProp); //output: 246
Now we finally see some getter/setter nature...!
While it's ideal not to have specification changes, you can't always guarantee that you can change the calling side... Properties are strong in case of emergencies.
Thinking of them as "class member variables that you can manage later" is reassuring! While their everyday usability is just as practical as what other languages call "class member variables," properties are quite robust when you inevitably need to change the implementation.

Properties Can Be Made Secure
Properties allow for various access control options compared to fields, so (if utilized properly) your code becomes more secure.
// init accessor: achieves immutability
public int IntProp { get; init; }
// Read-only with a default value specified
public int IntProp2 { get; } = 10;
// Read-only from outside, writable from within
public int IntProp3 { get; private set; }
// Required property: must be defined during initialization
public required string StringProp { get; set; }
// Combination: Required initialization and immutable
public required int IntProp4 { get; init; }
// Set-only properties cannot be made as auto-implemented properties, but are still possible
int _setOnlyProp;
public int SetOnlyProp { set => _setOnlyProp = value; }
In particular, init and required can make your code more secure. Moreover, because they require minimal code, you can use them without being overly conscious of getters/setters.
Immutability in "record" types is also based on init-only properties
By the way, the primary constructor of a record type internally creates properties with init accessors.
// record's primary constructor
record Person(string Name, DateTime Birthday);
// Internally, this is what's created
class Person
{
public string Name { get; init; }
public DateTime Birthday { get; init; }
public Person(string Name, DateTime Birthday)
{
this.Name = Name;
this.Birthday = Birthday;
}
public void Deconstruct(out string Name, out DateTime Birthday)
{
Name = this.Name;
Birthday = this.Birthday;
}
}
In modern C#, when we talk about safe and immutable data types, we talk about record, so properties contribute significantly to the safety of records.
Use Case for Properties: Data Binding in the MVVM Pattern
In standard .NET UI frameworks over the years (such as MAUI and WPF), the concept of the MVVM pattern has become widespread[2].
These UI frameworks use an XML-based format called XAML for the View. By performing data binding with the properties of a ViewModel class, the system ensures that changes to a property are immediately reflected in the appearance.
In older MVVM libraries, you had to write cluttered boilerplate code within properties. However, in recent, modern MVVM libraries, properties remain almost exactly like simple auto-implemented properties.
<TextBlock Text="{Binding Name}" />
// For CommunityToolkit.Mvvm v8.4+
[INotifyPropertyChanged]
public partial class MyViewModel{
[ObservableProperty]
public partial string Name { get; set; }
}
// For Epoxy
[ViewModel]
public sealed class MyViewModel{
public string? Name { get; set; }
}
In other words, properties are used extensively in the MVVM pattern for C# UI programming, and nowadays, they are hardly even thought of as getters/setters.
Looking at this, you can specifically see why the explanation that "properties are just getters/setters" is slightly off or insufficient, at least in the context of C# UI programming.
Use Case for Properties: Hook Points for Source Generators
In modern C#, there is a mechanism called "Source Generators" (SG) that automatically generates code during compilation to minimize boilerplate.
SGs are crucial for "NativeAOT" (native binary output) support, so almost all new .NET libraries highlight their NativeAOT compatibility by utilizing SGs.
And the key to these SGs is "Properties." An approach we've been seeing frequently lately is using properties as the hook point for SGs to automatically generate implementations.
In C# 13.0, it became possible to define partial properties. This allows you to create a property as a hook point for an SG to implement automatically...!
partial class C
{
// Defining declaration
public partial string Prop { get; set; }
}
Actually, the previous CommunityToolkit.Mvvm example was also an SG for properties. Like GeneratedRegex, the number of heavily used SG mechanisms that find properties to be the ideal target will likely continue to increase...
Properties are going to remain incredibly important!
Future Properties: the field Keyword
Among the examples provided so far, there are actually cases that will become even easier to write in the upcoming C# 14.0.
class A{
int _intProp;
public int IntProp
{
get => _intProp;
set
{
// Due to a specification change, we now record double the value!
_intProp = value * 2;
}
}
}
// Set-only properties cannot be made as auto-implemented properties, but are still possible
int _setOnlyProp;
public int SetOnlyProp { set => _setOnlyProp = value; }
These two will be able to be written as follows:
public int IntProp
{
get;
set => field = value * 2;
}
// set-only
public int SetOnlyProp { set => field = value; }
Whoa! So convenient!!
You won't need to declare the backing field manually anymore.
Are Properties Slow?
"Properties are functions under the hood, so they involve function calls. Therefore, they're slow. You should avoid them in performance-critical areas."
There is an occasional discussion like this.
Certainly, no matter how simple a C# property is, it translates to a function call when converted to intermediate code (IL). Looking at this, it seems like it might be slow due to the overhead of the call.
No Need to Worry About Auto-Implemented Properties
However!
If it's an auto-implemented property, you don't need to worry about it!
Optimizations occur at runtime, making them no different from fields.
public int Prop { get; set; } // Auto-implemented property
public int Field; // Field
public int GetProp() => Prop; // Property access
public int GetField() => Field; // Field access
C+Test.GetProp()
L0000: mov eax, [ecx+4]
L0003: ret
C+Test.GetField()
L0000: mov eax, [ecx+8]
L0003: ret
Even in the old and performance-wise mediocre ".NET Framework" runtime, optimizations are applied so that there is almost no difference between auto-implemented properties and fields.
Strictly speaking, there's a tiny difference, but if you're worrying about that, there are other things like algorithms that you should be focusing on more.
Cases to Watch Out For: Complex Properties and Asynchronous Processing
You need to be careful when you implement complex logic within a getter or setter. Since they look identical to fields from the outside, people might access them casually, which can lead to issues.
// Huh? I'm not heavy. I'm just a field (looking).
public int IamNotHeavy => DoHeavySomething();
// Oh no! (Heavy processing is executed every time!)
var p1 = this.IamNotHeavy; // 1st time: Heavy processing runs
var p2 = this.IamNotHeavy; // 2nd time: Heavy processing runs again
Also, properties cannot be async / await, so if you need to involve asynchronous processing, it's better to turn it into a method.
public int HeavyProp
{
get {
// You cannot await asynchronous processing inside a property
// return await DoHeavySomethingAsync()
// You could call it like this, but it will DEADLOCK!!!
return DoHeavySomethingAsync().Result;
}
}
Treat properties primarily as variables, and if that's not the case, stick to using methods.
Summary
Current State of Properties
- Properties ≠ Simple Getters/Setters: In modern C#, their uses are broad and their importance is extremely high.
-
Auto-implemented Properties are Mainstream: Used in the form
{ get; set; }, allowing use without being conscious of getters/setters. - Official Recommendations: Use properties instead of fields for visible members (CA1051).
Benefits of Properties
- Resilient to Specification Changes: You can change internal implementation without affecting the caller.
-
Improved Safety: Write robust code using
init,required, and access control. - Performance: Auto-implemented properties perform almost identically to fields.
Where to Use Properties
- MVVM Pattern: Play a central role in data binding within UI frameworks.
-
Source Generators: Act as hook points for automatic code generation via
partialproperties. -
recordTypes: The underlying technology for immutable data types.
Points to Watch Out For
- Avoid Heavy Processing: Hiding complex logic in properties can lead to unexpected delays.
- No Asynchronous Processing: Since async/await cannot be used, turn it into a method if asynchronous processing is required.
Future of Properties
-
fieldKeyword (Planned for C# 14.0): Allows for more concise syntax by automatically generating backing fields.
Conclusion: In modern C#, properties are positioned as a core language feature that goes beyond simple getters/setters.
By moving a step forward from the traditional understanding of "property = getter/setter" and reframing them as "property = flexible and secure class members," you'll be able to write more effective C# code... hopefully!
-
at the
Recommendedlevel or higher ↩︎ -
The MVVM pattern itself reportedly originated with WPF ↩︎
-
It's reportedly 20 times faster on NativeAOT than the traditional
Regexsyntax ↩︎
Discussion
ref 戻り値を使えば プロパティだって フィールドの様に 参照を返すことができるわかる(フィル―ドをプロパティにしてもそんな困ることはあんまないわかる)
https://sharplab.io/#v2:C4LgTgrgdgPgAgJgAwFgBQiCM6De6AEh+AbgIZgn4C8+UApgO74DCANqQM4eYAUAlAG4CRMHQBm+AJZRgJUqwh1q+UROIA6AGrzFQtEXxxMATh4ASAEQ5iAXwuDhhMgqU0Eeg0dOXrdh2htcRzkKYmV6JjZODgR+DxFxKRk5F2VVEi0dOnjCL3MrW3sclMVld2C8n0L/QLR0OABmQwQWdi5MfDx9ImlZAH1nXQqm9N78bVScAHM6WSoAPhVEgayBWs8mgHtiOjAwSQATJSMkfAAVTYBlYH2oKf5qRZ8oUgBbOk2xHij2vhscAEvd6fHgTRR/EA4MF0Gywix6WqNZqtaItLobJKyaHFJHbXb7I6GTCnC7XW73PiPfDPN4fL4/GJ/AE4IF00FZCFQrKwuwIoA=