Search code examples
c#oopgetter-setter

Getters and Setters - How does "value" work, particularly in an if statement?


I've been working through this video: https://www.youtube.com/watch?v=GhQdlIFylQ8&t=11038s

I am working through "Getters & Setters" at 3:54:60 (other subjects for C# are in the description for any needed context).

This is a class that I've made in order to print to the Console as well as a "Getter and Setter".

class Song
{
    private string title;
    public string artist;
    public int duration;

    public Song(string aTitle, string aArtist, int aDuration)
    {
        title = aTitle;
        artist = aArtist;
        duration = aDuration;
    }

    public string Title
    {
        get { return title; }
        set {
            if (value == "Hello")
            {
                value = "ERROR";

            } else
            {
                title = value;
            }
        }
    }
}

And this is the "Main" sort of code to print out the titles of two Song objects: "hello" and "kashmir".

class Program
{
    static void Main(string[] args)
    {
        Song hello = new Song("Hello", "Adele", 400);
        Song kashmir = new Song("Kashmir", "Green Day", 200);

        Console.WriteLine(hello.Title);
        Console.WriteLine(kashmir.Title);
        Console.ReadLine();
    }
}

However, I've tried to experiment with the "Getters and Setters" by seeing how I could print out something other than the song titles.

When I run the program, it prints out Hello and Kashmir both on separate lines.

How do I get it to print ERROR or something other than the song titles (or what other ways could I do this)?


Solution

  • There's a sorta funny thing going on here that even seasoned devs occasionally trip over...and it's missing the difference between a backing field and a property. This happens from time to time...and absolutely baffles the dev until they realize they've made a Visual Studio intellisense-assisted error. It's doubly likely if you name your backing field the same as the property name...differing only in case.

    class Song
    {
        private string title;  //--> this is the "backing field" for the property "Title"
        public string artist;
        public int duration;
    
        public Song(string aTitle, string aArtist, int aDuration)
        {
            //title = aTitle; //--> this only sets the backing field...not the "Title" property
            Title = aTitle;  //--> this sets your "Title" property
            artist = aArtist;
            duration = aDuration;
        }
    

    The next issue is that, in a property set, the value is the incoming suggested value for the property. You don't have to accept it. Your job in the property set is to validate the incoming value, and put it into the backing field if you like it...or maybe put something else in if you don't. Changing the incoming value is rarely what you want to do. You almost got it right...here's the commented fix:

        public string Title
        {
            get { return title; }
    
            set {
                if (value == "Hello")
                {
                    //value = "ERROR"; //--> this only changes the incoming value
                    title = "ERROR";   //--> this sets your backing field
    
                } else
                {
                    title = value;
                }
            }
        }
    }
    

    Having said all that, it's not at all uncommon to see the constructor set only backing fields, rather than going through the sometimes-expensive validating code of the property set. A lot of times, the property is the public API for the users of your type to set the value...while the constructor is kept internal or private and is only used to fill in values that had been saved off somewhere..like in a database. A good idea? Maybe/maybe not. As you've just discovered, bypassing the property set can leave you with something that might be an error.