Fields and Properties - Managing Object State in C#

Vaibhav • September 10, 2025

In the previous article, we explored how classes and objects form the foundation of object-oriented programming in C#. We saw how to define a class, create objects, and use fields and methods to represent and manipulate data. Now, we turn our attention to a more refined way of managing object state: fields and properties.

Fields are the basic building blocks for storing data inside an object. Properties, on the other hand, provide a controlled and flexible way to access and modify that data. In this article, we’ll explore how fields and properties work, how they differ, and how to use them effectively to write clean, maintainable, and encapsulated code.

Understanding Fields

A field is a variable that belongs to a class or object. It stores data that represents the state of the object. Fields are typically declared with an access modifier (like public or private) and a type.

class Book
{
    public string Title;
    public string Author;
    public int Year;
}

In this example, the Book class has three public fields: Title, Author, and Year. These fields can be accessed and modified directly from outside the class.

While public fields are simple and convenient, they expose the internal state of the object to the outside world. This can lead to unintended side effects and makes it harder to enforce rules or validation.

Encapsulation with Private Fields

To protect the internal state of an object, fields are often declared as private. This means they can only be accessed from within the class itself. To allow controlled access to these fields, we use properties.

class Book
{
    private string title;
    private string author;
    private int year;

    public string GetTitle()
    {
        return title;
    }

    public void SetTitle(string value)
    {
        title = value;
    }
}

This approach uses methods to get and set the value of a private field. While effective, C# provides a more elegant and idiomatic way to do this: properties.

Introducing Properties

A property is a member that provides a flexible mechanism to read, write, or compute the value of a private field. Properties use get and set accessors to define how values are retrieved and assigned.

class Book
{
    private string title;

    public string Title
    {
        get { return title; }
        set { title = value; }
    }
}

Now, instead of calling GetTitle() or SetTitle(), you can simply use the property:

Book b = new Book();
b.Title = "C# in Depth";
Console.WriteLine(b.Title);

This syntax is cleaner and more intuitive. Behind the scenes, the property still uses the private field, but it allows you to add logic to the get and set blocks if needed.

Auto-Implemented Properties

For simple cases where no additional logic is needed, C# allows you to use auto-implemented properties. These properties automatically create a hidden backing field.

class Book
{
    public string Title { get; set; }
    public string Author { get; set; }
    public int Year { get; set; }
}

This is equivalent to manually defining private fields and simple get/set accessors. Auto-properties are ideal for data models and DTOs (Data Transfer Objects) where you just need to store and retrieve values.

Read-Only and Write-Only Properties

You can control access to properties by omitting either the get or set accessor. A property with only a get is read-only, and one with only a set is write-only.

class User
{
    public string Username { get; }
    public DateTime CreatedAt { get; }

    public User(string username)
    {
        Username = username;
        CreatedAt = DateTime.Now;
    }
}

In this example, Username and CreatedAt are read-only properties. Their values are set in the constructor and cannot be changed afterwards.

Validation in Property Setters

One of the key advantages of properties over public fields is the ability to add validation logic in the set accessor. This allows you to enforce rules and prevent invalid data.

class Product
{
    private decimal price;

    public decimal Price
    {
        get { return price; }
        set
        {
            if (value < 0)
                throw new ArgumentException("Price cannot be negative.");
            price = value;
        }
    }
}

Now, if someone tries to set a negative price, the program will throw an exception. This kind of defensive programming helps catch errors early and keeps your objects in a valid state.

Calculated Properties

Properties don’t have to store data - they can also compute values based on other fields. These are called calculated properties.

class Temperature
{
    public double Celsius { get; set; }

    public double Fahrenheit
    {
        get { return Celsius * 9 / 5 + 32; }
    }
}

In this example, Fahrenheit is calculated from Celsius. You can read it like a regular property, but it doesn’t store a value - it computes one on the fly.

Using Properties with Object Initializers

Properties work seamlessly with object initializer syntax, which allows you to set property values when creating an object.

Book b = new Book
{
    Title = "Effective C#",
    Author = "Bill Wagner",
    Year = 2020
};

This syntax is concise and readable, especially when creating objects with multiple properties. It’s commonly used in real-world applications and frameworks.

Backing Fields and Property Design

When you use full properties (not auto-properties), you typically store the value in a backing field. This gives you flexibility to add logic around getting and setting the value.

class Account
{
    private string passwordHash;

    public string Password
    {
        set { passwordHash = Hash(value); }
    }

    private string Hash(string input)
    {
        // Pretend hashing logic
        return "hashed_" + input;
    }
}

In this example, the Password property is write-only and stores a hashed version of the input. The backing field passwordHash is private and not exposed.

Properties vs Methods

Properties are ideal for accessing and modifying data. Methods are better suited for performing actions. If something feels like a value - use a property. If it feels like a command - use a method.

user.Name = "Vaibhav";      // Property - setting a value
user.Login();              // Method - performing an action

This distinction helps keep your code intuitive and consistent. Properties should be fast and predictable, while methods can perform more complex operations.

Summary

Fields and properties are essential tools for managing object state in C#. Fields provide raw storage, while properties offer a controlled and flexible interface for accessing and modifying that data. By using private fields and public properties, you can encapsulate your objects, enforce validation, and maintain a clean separation between internal implementation and external interface.

Auto-properties simplify code for straightforward cases, while full properties allow for custom logic and validation. Calculated properties let you derive values dynamically, and object initializers make it easy to set properties when creating objects.

As you continue building C# applications, mastering properties will help you write code that is robust, maintainable, and aligned with object-oriented principles.

In the next article, we’ll explore Constructors - how to initialize objects properly, enforce required values, and ensure that your objects start life in a valid and consistent state.