Properties
The Crash Course
- Properties provide a quick and effective approach to creating getters and setters for instance variables.
- You can create a property with code like the following:
public int Score { get { return score; } set { score = value; if (score < 0) { score = 0; } } }
- Not all properties need both a setter and a getter.
- Getters and setters can have different access modifiers.
- Auto-implemented properties can be created that allow you to quickly define a simple property with default behavior (public int Score { get; set; }).
Introduction
Remember in the previous tutorial, how I talked about how it is common to have lots of times that you want to "get" the value of an instance variable, or "set" the value of that variable, and as a result, you may be making lots of GetSomething() and SetSomething() methods?
C# has a very powerful feature that makes it easy to create a way for other programmers to get or set the value of an instance variable, called properties.
This tutorial will discuss why properties are so helpful, and how to create them in several different ways. It also discusses how when you create an instance of an object, that you can set a bunch of properties all at once, right at the beginning.
The Motivation for Properties
So imagine you are creating a simple class that looks like this, so far:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Properties { class Player { private int score; } }
Let's say that you want to be able to have something outside of the class be able to set the value of score, and also be able to get the current value of the score.
The "classic" way (and if you're coming from a Java background, the only way) is to create a method that returns the value of score and another one that sets the value of score, possibly with some extra logic to check to make sure that the score is valid (like non-negative).
This would be done like this:
public int GetScore() { return score; } public void SetScore(int score) { this.score = score; if(this.score < 0) { this.score = 0; } }
The need for this is extremely common. However, it is a little frustrating to always have to type SetScore(10); It is tempting to just make score public instead of private. Then you could simply say score = 10;. That would be very convenient, except for one problem: now the instance variable is public, and anyone can mess it up (like assign a negative value, or something).
C# has a feature that solves all of these issues: properties. Let's see how to create a property.
Creating Properties
A property is simply an easy way to create these get and set methods that is very readable.
Instead of the two methods that we showed in the previous code snippet, we could instead do this:
public int Score { get { return score; } set { score = value; if (score < 0) { score = 0; } } }
This creates a Score property. We can see that it is public, so anyone can use it (though we could also use private if we had wanted). We also specify the type of the property, which in this case is an int. Then we give it a name.
We then use the get and set keyword to show what should happen when someone tries to read the value of the property or set the value of the property. The code inside of the curly braces is essentially the exact same code that was in the GetScore() and SetScore(int) methods, with only one difference.
With a normal method (like SetScore), we can pass in a value to set for the variable. In a property, we use the value keyword instead. This takes on the value of what the person calling the property is trying to set.
So now we can call our property using something like this:
Player player = new Player(); int currentScore = player.Score; player.Score = 50;
When we try to read from the Score property, the code inside of the get block of the property gets executed and returned. When we try to assign a value to the Score property, the code inside of the set property gets executed. And in this case, the value 50 gets put into the value keyword inside of the set block.
Properties easily allow us to make mechanisms for getting and setting variables, including doing extra work of validating what the user is trying to set, without making our code more difficult to read.
It is worth mentioning that properties are essentially just "syntactic sugar". Behind the scenes, the C# compiler is turning these into methods that do the same stuff.
One other thing that we should discuss here, just to make things clear, is that a property does not necessarily need to belong to an instance variable. In the code we've done with properties so far, this has been the case. But it doesn't have to be that way. Let's look at another example where this isn't the case:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Properties { class Time { private int seconds; public int Seconds { get { return seconds; } set { seconds = value; } } public int Minutes { get { return seconds / 60; } } } }
You can see here that we have a seconds instance variable, along with a Seconds property that lines up with it. (By the way, using lower case names for instance variables, and upper case names for the matching property is very common.)
In addition, we also have a Minutes property that doesn't belong to any instance variable. There's no minutes instance variable at all. Instead, we just do some other work—in this case, return the number of seconds divided by 60.
One other thing this shows us is that we do not need to necessarily provide both a set and a get accessor for the property. Either one is optional, though at least one is required. If you only have a "getter", then the property is "read-only", because you can't set it. If you have only a "setter", well, then… that's kind of strange, because you'd only be able to set a value, but never read it. So what good would it do you? (Though there are a few times where this could be meaningful. But it is pretty uncommon.)
Different Accessibility Levels
So far, when we've seen a property, they've all been public, meaning anyone has access to both the getter (the get block) and the setter (the set block). We also just saw an example where we provided only a getter for the property.
Sometimes, though, we have a property and we want to be able to have the accessibility levels different for the getter and the setter. For instance, allow the getter to be public, but make the setter private.
This is easy to do, because you can specify an access modifier before the get or set keywords, like this:
public int Score { get // This is public by default, because the property is marked 'public' { return score; } private set // This, however, is now private. { score = value; } }
So in this example, anybody will be able to use the getter, while you will only have access to the setter from inside of the class that it belongs to.
Auto-Implemented Properties
You will probably find yourself making a lot of things that look something like this:
private int score; public int Score { get { return score; } set { score = value; } }
A new feature in C# 3.0 was the ability to create auto-implemented properties that do the exact same thing. Instead of any of the code above (including the private instance variable score), you could simply say:
public int Score { get; set; }
This makes a default instance variable behind the scenes, and simple get and set code. Of course, though, you won't have access to the private instance variable in this situation, though, because it doesn't exist. But it is a nice shorthand way to create a property.
Setting Properties when Creating an Object
There's one other interesting thing that we should discuss when we talk about properties. Let's say you have a Player class like in the previous tutorial that has instance variables for the player's name, score, and number of lives left. Let's also say that you create properties for each of those, called Name, Score, and LivesLeft.
When you create a new Player object, you can use the following syntax to assign values to the Properties, right when you create the object, like this:
Player player = new Player("Frankenstein") { Score = 100, LivesLeft = 7 };
This prevents us from needing to do this:
Player player = new Player("Frankenstein"); player.Score = 100; player.LivesLeft = 7;
Instead, we can combine it all into one line.
What's Next?
That covers all of the important things about properties.
The next thing we want to go over is something very similar in appearance (but actually quite different in implementation) to a class: a struct.
thanks for the tutorials, they are very helpful. I came from c++ and I wanted to learn this language because I was told that the dev type for games was faster.
Development times in C# will usually be much faster than C++. (Though naturally, it depends on the skill level of the C# programer and the C++ programmer.) At any rate, I'm glad you're here, and good luck making games!
By far the best programming tutorials I have ever read. Thank you.
Thanks, Sean!
I am confused about something. If properties don't need instance variables, then why use instance variables at all? In your book, under the using properties try it out, you don't make instance variables for several colors, instead you made properties. Should I be skipping (private) instance variables and using properties instead? Thanks.
Auto-properties do technically have an instance variable as a backing field, even though you don't have direct access to it. The C# compiler creates one.
Private instance variables with no associated property, auto properties, and your own properties with a specific named private instance variable as a backing field all have their place, and they're all used quite regularly.
Use just a private instance variable when you don't want anybody to have access to it. (When it's just implementation details, as opposed to being part of the class's public interface (I'm using "interface" loosely here, not referring specifically to C# interfaces, though they're conceptually related).
Use an auto-property when the data is a part of the public API/interface of the class (when "outsiders" need to be able to access that piece of data) but when there is no special logic required to validating the data. (Auto properties don't give you an opportunity to run any sort of logic when the backing field is getting set.)
Use a regular property with your own instance variable backing field when some custom logic needs to be ran every time it gets set (or someone attempts to set it). This might be making sure the value being set is within a certain range, or raising an event when it gets set or something.
One other option is to just use a plain old method. The syntax of a property gives the impression that you're just setting a value in a variable, which executes really fast. With a property, there's always going to be a little extra logic involved, so it's not quite as fast. (At the very least, there's the overhead of calling the property.) A little extra logic isn't a problem, but if your setter (or getter) requires a lot of extra work, it would be worth considering just using a normal named method for getting and/or setting a piece of data. With a property, there's this illusion that it's just writing to a variable and will be fast. Even though it's always a little more than just writing to a variable, people expect it to be fast. If it's not, making it a method instead (which people don't necessarily assume will be fast) will come out feeling more natural to users of your class.
Hope that clarifies it a bit.
Post preview:
Close preview