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.