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

  • Use expression-bodied properties for simple `get` accessors.
  • Consider using private setters to enforce immutability, especially for value objects.
  • Clearly document the purpose of private setters and why a property's value is restricted.
  • Balance immutability with the need for flexibility. Sometimes, mutable objects are more appropriate.

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

  • Conciseness: Expression-bodied properties provide a more compact syntax.
  • Immutability: Private setters allow you to create immutable or semi-immutable objects.
  • Readability: Using expression-bodied properties and private setters can improve code readability.
  • Thread Safety: Immutable objects are inherently thread-safe.

Cons

  • Less Flexibility: Immutability can make it more difficult to modify object state.
  • Potential Performance Overhead: Creating new objects instead of modifying existing ones can have performance implications in some scenarios.
  • Complexity: Overuse of immutability can make code more complex to understand.

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.