In this article, we will learn about the difference between Properties and Fields in C#, and how to use them.

To download the source code for this article, you can visit our GitHub repository.

Let’s begin!

What Is a Field?

We call a variable that we directly declare in a class or struct a “field” in C#. Fields can be of any type and can be public, private, protected, internal, protected internal, or private protected. These access modifiers used with our fields define their level of access:

Support Code Maze on Patreon to get rid of ads and get the best discounts on our products!
Become a patron at Patreon!

private int _age;

Here, _age is a field of type int and is marked private, meaning it can only be accessed from within the class.

A common use case for fields is as a backing store or backing field. This is when we declare a field as private and use it to store data accessed by a public property.

Let’s declare an Age property and use the _age field as its backing field:

public int Age
{
    get { return _age; }
    set { _age = value; }
}

When we instantiate an object, the compiler initializes the fields before calling the object constructor. However, we can overwrite any value that the field has at the time of declaration.

Let’s see this in action by creating a Person class:

public class Person
{
    private string _name = "John Doe";

    public Person()
    {
        Console.WriteLine(_name);

        _name = "Jane Doe";
    }

    public void UpdateName(string name)
    {
        Console.WriteLine(_name);

        _name = name;

        Console.WriteLine(_name);
    }
}

Here, we set a value to the _name field at the time of declaration. Then, we update the value in the constructor. Finally, we provide an additional means to update the value using the UpdateName() method. 

Now, if we instantiate this class object and call the UpdateName() method:

var person = new Person();
person.UpdateName("Sam Doe");

We see the field value being updated thrice in the console output in the order we updated the values:

John Doe
Jane Doe
Sam Doe

Types of Fields

We can declare a field readonly. This means that we can only assign a value to the field at the time of declaration or within the constructor. Making the _name field read-only would cause a compiler error in the UpdateName() method.

Another keyword that we can use with a field is static.

Once we declare a field as static, the field gets associated with the type itself rather than with instances of the type. This means that we have only one instance of the static field across all instances of the class within the same application domain. The static fields are accessible without instantiating the type, similar to global variables.

In essence, a static field acts as a “singleton” within the context of the application, ensuring a single shared value across all instances of the class.

Let’s add a static Age field:

public class Person
{
    public static int Age;
    private string _name = "John Doe";
}

We can now access the Age field without instantiating a Person object:

Person.Age = 19;

A field can be both static and readonly at once. The static readonly fields are similar to constants. However, in contrast with constants, their values are resolved at runtime rather than at compile time.

We can declare a field as required. This requires us to initialize the required field by an object initializer when creating an object. Let’s declare a required HasSuperPowers field in the Person class:

public required bool HasSuperPowers;

This triggers a compiler error “Error CS9035 Required member ‘Person.HasSuperPowers’ must be set in the object initializer or attribute constructor”. To fix this error, we need to add an object initializer:

var person = new Person { HasSuperPowers = true };

Since C# 12, we have primary constructors that can act as a replacement for the fields. The parameters of a primary constructor can initialize properties or fields used as variables in methods or local functions. In addition, we can pass them to a base constructor.

Now that we’ve gone over fields in C#, let’s take a look at properties.

What is a Property

In C#, properties are a way to encapsulate private fields, providing controlled access to them through getter and setter methods. We use the get accessor to retrieve the value of the property and the set accessor to assign the value to the property. The set  accessor has an implicit parameter called value, with a type matching that of the property.

We have properties with a backing field like the Age property we saw earlier:

public int Age
{
    get { return _age; }
    set { _age = value; }
}

We can also have auto-implemented properties:

public string Name { get; set; }

These properties automatically generate a private backing field and provide a default implementation for the get and set accessors.

Types of Properties

Both of these properties are “read-write” properties. We can also have “read-only” properties with only get accessors, or “write-only” properties with only set accessors. Let’s create a Configuration class:

public class Configuration
{
    private string _secretKey = string.Empty;

    public string SecretKey
    {
        set
        {
            _secretKey = $"**{value}**";
        }
    }

    public string MaskedSecretKey
    {
        get { return _secretKey; }
    }
}

Here, we mask the actual value for security reasons using the “write-only” SecretKey property. Then, the MaskedSecretKey property, which is a “read-only” property, can be used to retrieve the masked value.

Init Only Properties

Since C# 9.0, we also have an init accessor available. This allows us to set the initial value of a property during object creation, but then prevent further modifications to that property:

public class Rectangle
{
    public double Width { get; init; }
    public double Height { get; init; }
}

Now, we can create an instance of the Rectangle class and set its properties:

var newRectangle = new Rectangle { Width = 10, Height = 5 };

However, we can’t modify these properties later:

newRectangle.Width = 15.0;

This gives us a compiler error.

Static Properties

Similar to the fields, we can add access modifiers to properties to control their accessibility. We can also declare properties as static using the static keyword. For example, we can add a static ScalingFactor property to the Rectangle class:

public static double ScalingFactor { get; set; } = 1.0;

Because static properties are bound to the class itself, rather than a specific instance, we can directly access them without instantiating a class:

Rectangle.ScalingFactor = 2.0;

Now, let’s create a CreateScaledRectangle() method to apply scaling:

public Rectangle CreateScaledRectangle()
{
    return new Rectangle(Width * ScalingFactor, Height * ScalingFactor);
}

Finally, let’s create another Rectangle and scale it:

var newRectangle = new Rectangle { Width = 10.5, Height = 5.5 };
var newRectangleScaled = newRectangle.CreateScaledRectangle();

Console.WriteLine("Dimensions of the new rectangle after scaling: "
    + $"{newRectangleScaled.Width} X {newRectangleScaled.Height}");

We observe that the scaling factor we set previously (2.0) is applied to the newRectangle object, even though we did not set a scaling factor during its construction:

Dimensions of the new rectangle after scaling: 21 X 11

This is because there is only one instance of the static property across all instances of the class within the same application domain.

Virtual and Abstract Properties

A property can be declared as virtual by marking its accessor using the virtual keyword. Virtual properties allow inheriting classes to override them using the override keyword. With virtual properties, we can provide a default behavior for the property in our class but still allow inheritors to define specific behavior.

We can also declare a property as abstract, but this can only be done within an abstract class. Abstract properties do not provide an implementation in the base class but rather require deriving classes to provide an implementation.

Difference Between Properties and Fields

The major differences between properties and fields in C# lie in their accessibility, encapsulation, and the level of control they provide over data access.

Accessibility and Direct Access

Fields provide direct access to data and are often declared with keywords like private, public, or protected to specify their visibility. They lack the protective mechanisms of encapsulation, making them directly accessible from outside the class.

Properties, on the other hand, encapsulate data and control access through accessors. This allows for more controlled visibility and modification of data.

Encapsulation

Fields lack encapsulation, meaning they can expose data without any inherent protection or validation, like a field with public access modifier which allows for direct access from outside the class.

Properties encapsulate data, enabling us to control how we access and modify the data. For example, by using validation logic we can ensure that we only set valid and desired data.

Usage of Get and Set Accessors

We access the fields directly without the need for explicit accessors. Whereas, properties utilize get and set accessors, allowing for additional logic during access or modification. For instance, we can introduce a validation logic for a rectangle’s width:

public double Width
{
    get => _width;
    init
    {
        if (value < 0)
            throw new ArgumentException("A Rectangle can't have negative width",
                nameof(value));

        _width = value;
    }
}

This is only possible using properties.

When To Use Properties and Fields

One of the main differences between Properties and Fields involves data encapsulation. Another major difference is regarding computations or validations we may wish to perform when data is read or written. Both of these are things we need to consider when choosing between exposing our data as a Field or as a Property.

Difference Between Properties and Fields Regarding Encapsulation

Because Fields provide direct access to data they are suitable when simple data access is a priority. Fields are useful for a simple domain model and other scenarios where we don’t need to perform extra validation on the values within our application. Because of the direct access to the data, the caller of our class or struct can directly modify the internal state of the object. 

On the other hand, Properties allow us to control access to the underlying data structure while also providing a means for additional validation or computation. This encapsulation allows us to ensure that our object maintains a valid internal state.

Difference Between Properties and Fields Regarding Computed Values

While Fields provide simple and direct access to the underlying data, Properties have the added advantage of allowing us to perform computations on the data before either setting or returning the value.

For example, we may have a class modeling the temperature. Internally we store the value in Kelvin. We can then provide Property accessors which will enable callers to both get and set the value in either Fahrenheit or Celsius, something that would not be possible with direct Field access.

Conclusion

In this article, we learned about fields and properties in C#. We looked at how to use them and when to use one over the other. The choice between them depends on the desired level of control and encapsulation for a particular data member within a class.

Liked it? Take a second to support Code Maze on Patreon and get the ad free reading experience!
Become a patron at Patreon!