✨ Shield now has support for Avalonia UI

Fields vs Properties in C# OOP — Which one should you use?

Sep 25, 2023 | .NET, C#

Understanging “Fields”

In the object-oriented programming (OOP) approach of C#, a field is a class or struct level variable that holds data specific to an instance (object). It forms the identity of an instance, named as instance fields.

Try and keep your variables private (common practice to have an underscore as prefix) to prevent external access and only expose via properties or methods.

Do you keep your treasure box locked and hidden? That’s what private variables are like. They are “hidden” within a class, typically prefixed with an underscore for easy recognition. Luckily, we do not have to break into this box as we have special keys – properties or methods – that allow careful access to them.

Creating fields in a class would be like this:

public class Person{
    // declare a private field to store name
    private string _firstName;
    // declare another private field to store title
    private string _jobTitle;
}

Look at our code snippet, see how the fields are kept private? This ensures we are in total control of how these hidden treasures – _firstName and _jobTitle fields – can be accessed or modified, promoting data integrity and security.

Fields are present not only within the essence of a class, but you can also encounter them in:

  1. Structs: Picture your toy building blocks – you have to assemble each piece separately, right? Likewise, struct fields are not assigned any value upfront; they have to be initialized individually while crafting a new struct instance.
  2. Nested classes: Have you ever noticed how Russian dolls fit inside each other? Nested classes are just that. They’re classes snugly wrapped inside another class. But guess what? Those fields you sneak inside these nested classes can only be found and played with within that doll or its parent.
  3. Partial classes: Do you love doing puzzles? Partial classes would appeal to you. They’re like puzzles; you piece together a class step-by-step, with files spread across. You don’t have to declare all fields in one piece (file); you sprinkle them across the puzzle pieces (files), eventually melding to form one beautiful class (completed puzzle).

The necessity for a “Field” within a class structure

Fields in your code are like the secret compartments in your diary. You can choose who gets to see (access) what’s inside based on their clearance levels, like private, protected, and public.

Let’s try to modThis makes diary-keeping (coding) more disciplined, easy to manage, and prevents meddling in your affairs, doesn’t it?

Let’s draw this out via a fun snippet:

public class Codename{
    private string _firstName; // They know me as this
    private string _lastName; // But that ain't my real identity

    // Mocking a secret agent
    public Codename(string firstName, string lastName){
        this._firstName = firstName; // Public identity
        this._lastName = lastName; // Private identity
    }

    public string GetFirstName(){ // They call me by this name
        return _firstName;
    }

    public void SetFirstName(string firstName){ // Maybe I need to change my cover name
        this._firstName = firstName;
    }

    public string GetLastName(){ // My true self is only known to a few
        return _lastName;
    }

    public void SetLastName(string lastName){ // Sometimes, even I have to change my real name
        this._lastName = lastName;
    }

    public void AppendLastName(string tail){ // Like to add some style to my real name
        _lastName += tail;
    }

    public string RevealIdentity(){ // Only for those top-level clearance guys
        return $"{_firstName} {_lastName}";
    }
}

Did you see how fields helped keep our agent’s identity under wraps, while still aiding in mission’s performance? Cool, right?

So, where does a “Property” fit in all this?

Properties appear as special methods, sporting capabilities of getter and setter methods of fields, though don’t be misled, they perform equally good in both run-time and compile-time.

If fields encapsulate data, properties encapsulate the mechanism to access and modify that data, making interaction with fields a more charming ordeal.

Once a property is invoked, it might appear like magic to you but under the hood, it’s the getter or setter method working its charm woven by our friend here – the compiler.

Let’s us experience this magic with a simple example:

// Simple class definition
public class Avatar{
    // Initialize private field
    private string _handle;

    // Property to access the private field
    public string Handle{
        get { 
            // This getter method fetches value of _handle
            return _handle; 
        }
        set { 
            // And here, setter method updates _handle's value
            _handle = value; 
        }
    }
}

Here, our private field _handle is linked to the Handle property. Convenient, right? But what if we just need a straightforward link, no added frills or checks, something naked or auto-implemented?

Relax, we got you covered:

// Simple class definition
public class Avatar{
    // Auto-implemented property
    public string Handle { get; set; }
}

Voila, we just crafted an auto-implemented property. Behind the scenes, it still creates a private field like before, only that this time it’s unbeknownst to us, hidden, with our Handle property secretly partaking in get & set affairs.

Alright, time to give our past Identity class example – the one that was partying with fields, getters, and setters, a grand makeover using properties:

// Class definition
public class Identity{
    // Private fields initialisation
    private string _moniker;
    private string _designation;

    public Identity(string moniker, string designation){
        // Assigning values to the fields
        this._moniker = moniker;
        this._designation = designation;
    }

    // Accessor and mutator for Moniker field
    public string Moniker{
        get { return _moniker; }
        set { _moniker = value; }
    }

    // Accessor and mutator for Designation field
    public string Designation{
        get { return _designation; }
        set { _designation = value; }
    }

    public void BolsterDesignation(string extraTitle){
        // Append the extraTitle to existing title
        _designation += extraTitle;
    }

    public string ComputeFullName(){
        // Returns the full name
        return $"{_designation} {_moniker}";
    }
}

Do you agree that after the makeover, our Identity class is more readable and maintainable than ever before? Such is the beauty of properties!

Be mindful of:

Ever got soaked in a Stack Overflow error? An inadvertent mistake of setting a Property’s variable same as Property’s name rather than Field’s name can land you there (knowingly or inadvertently).

This can trigger an infinite loop that gobbles up all your system memory, like Pac-Man munching on those marbles.

Let’s take a look at how this could happen with a code snippet:

// Defining a Class "Superhero"
public class Superhero{
    // Here's where the trouble starts. Setting the Property name and its variable name to be the same
    public string HeroName{
        get { return HeroName; } // "get" accesses the value
        set { HeroName = value; } // "set" assigns the value
    }
}

// This is our main program
static void Main(string[] args){
    Superhero superman = new Superhero();
    superman.HeroName = "Superman"; // Setting the property value
}

In the example above, when we set HeroName, instead of assigning this value to a field (like how rules of the universe should have been), it triggers the set section of the property — again and again in a never-ending loop. Consequently, creating a whirlpool and sucking all of memory space into its center.

Always remember to utilize your class fields and properties correctly to avoid such issues.

Remember, the path to data goes through Property’s getter or setter → relevant Field. So name them accordingly for smooth sailing.

You May Also Like