C# > Object-Oriented Programming (OOP) > Encapsulation > Property Accessors (get, set)
Encapsulation with Expression-Bodied Properties and Private Setters
This snippet demonstrates a more concise way to define properties using expression-bodied syntax and illustrates the use of private setters to enforce immutability or controlled modification. We'll create a `Circle` class where the `Radius` can be set upon instantiation, but the `Area` is calculated and read-only after that.
The `Circle` Class
This code defines a `Circle` class with a `Radius` property and an `Area` property. The `Radius` property has a `private set` accessor. This means that the `Radius` can only be set from within the `Circle` class itself, typically in the constructor. This prevents external code from directly modifying the radius after the circle has been created, enforcing a degree of immutability. The `Area` property is an expression-bodied property with only a `get` accessor. It calculates the area based on the current radius and returns the result. Because there is no `set` accessor, the `Area` is a read-only property.
public class Circle
{
public double Radius { get; private set; }
public double Area => Math.PI * Radius * Radius;
public Circle(double radius)
{
if (radius <= 0)
{
throw new ArgumentException("Radius must be positive.");
}
Radius = radius;
}
}
Using the `Circle` Class
This `Example` class demonstrates how to use the `Circle` class. A `Circle` object is created with a radius of 5. The radius and area are then displayed. The commented-out line `circle.Radius = 10;` would result in a compile-time error because the `set` accessor for the `Radius` property is private, preventing external modification.
public class Example
{
public static void Main(string[] args)
{
Circle circle = new Circle(5);
Console.WriteLine($"Radius: {circle.Radius}, Area: {circle.Area}");
// circle.Radius = 10; // This will cause a compile-time error because the setter is private.
}
}
Concepts Behind the Snippet
Expression-Bodied Properties: A concise way to define properties when the `get` or `set` accessor contains only a single expression. They use the `=>` operator. Private Setters: Restrict the ability to set the value of a property to only within the class itself. This is useful for creating immutable or semi-immutable objects where the property value is determined during object creation and should not be changed externally. Immutability: The practice of designing objects whose state cannot be changed after they are created. Immutable objects are thread-safe and can simplify code by eliminating the need for synchronization.
Real-Life Use Case
Consider a `DateTime` struct. The individual components of a `DateTime` (year, month, day, etc.) are typically not directly settable after the `DateTime` object is created. Instead, methods like `AddYears`, `AddMonths`, and `AddDays` are used to create *new* `DateTime` objects with modified values. This design promotes immutability and prevents accidental modification of date and time values.
Best Practices
Interview Tip
Be prepared to discuss the advantages and disadvantages of immutable objects. Understand how private setters contribute to immutability. Be able to provide examples of classes where immutability would be beneficial.
When to Use Them
Use expression-bodied properties when you have a simple `get` or `set` accessor that can be expressed as a single expression. Use private setters when you want to restrict the ability to modify a property's value from outside the class, promoting immutability or controlled modification.
Memory Footprint
Like standard properties, expression-bodied properties themselves don't directly impact the memory footprint. Private setters also have no direct memory overhead. The memory is determined by the underlying fields. Immutability can sometimes lead to increased memory consumption if creating new objects instead of modifying existing ones. However, this is often a worthwhile trade-off for the benefits of immutability.
Alternatives
You could use a standard property with a `get` and a `set` accessor, and throw an exception in the `set` accessor if you want to prevent modification after initialization. However, using a `private set` is generally cleaner and more explicit. Another alternative is to use a record, which is implicitly immutable in C# 9.0 and later.
Pros
Cons
FAQ
-
What is the purpose of a private setter?
A private setter allows you to control where a property's value can be set. It restricts setting the value to only within the class itself, often during object creation or through internal methods. This helps to enforce immutability or controlled modification. -
What is an expression-bodied property?
An expression-bodied property is a property defined using the `=>` operator. It's a shorthand way to define a property when the `get` or `set` accessor contains only a single expression. For example: `public string Name => _name;` -
How does a private setter contribute to immutability?
A private setter prevents external code from directly modifying a property's value. This, in combination with setting the property's value only during object creation (in the constructor), effectively makes the property immutable after the object is created.