Friday, April 19, 2024 13:02

Table of contents >> Objects > Properties

Properties

In today’s lesson, I will talk about one of the previous lesson’s new concepts. The first subject on the list: fields and properties. According to our beloved MSDN, a property is a member that provides a flexible mechanism to read, write, or compute the value of a private field. Properties can be used as if they are public data members, but they are actually special methods called accessors. The only thing that the above definition makes clear so far is that properties are in close relation to fields. So, to get started, lets take the Oven class example from the previous lesson:

At the top of my example, we have this portion, which we will analyze now:

In yesterday’s article, I said that a class can have Fields. The above lines are the fields of our Oven class, they are variables declared directly in our class, outside of any method, function, etc. There are many uses for fields, but in this particular example, they are used to store the values of the properties private, hidden. For instance, the property Weight is keeping its value private using the field variable weight. We haven’t learned yet about access modifiers, but you probably observed the keyword private in front of each field’s declaration. For now, just know that this makes the field accessible only from within the body of the class declaring that field, and invisible to the entire outside world. By convention, except specific cases, fields should always be private, and their value should be accessible to the outside world only through properties. To better understand this, lets look at the example of two properties:

First, if you read the lesson Formatting Codes, you should already be able to see that the two properties are synonym, even if they are written differently. The reason why I have written them in two different ways is because if we are writing our properties the way Model property is written, it will occupy a lot of lines, and your program will have a very big length. Compared with the second example of a property, which occupies 5 lines of code, the first one occupies 11. However, as we will see in future examples, properties can have additional lines of codes, in which case it is preferred that we use the first way of writing our properties. This is the reason why you should be aware of both ways of writing a property: whenever your property only gets or sets the value of a field variable, you can just write it in the “shortened” way, to save space.

Now, let’s actually see what these lines mean. First, you can notice that every property has a body contained between { } brackets, just like classes, methods, functions do. This is nothing we haven’t seen and learned already. Inside this body, we have two constructs: get and set.

We can only perform two actions on a property: either read it’s value, or assign a value to it. Get and set (also called accessors) do exactly this: get (also called “getter“) will always give us the stored value of the property, while set (also called “setter“) will always set a value to that property. So, when we write something like this:

the compiler will assign to the myOvenWeight variable the value of the Weight property of the Oven class, by internally using the get portion of the Weight property’s body. Likewise,

is an example of how we are assigning a value to the property Weight of the class Oven, in which case, internally, the compiler will execute the set portion of the property’s body.

Now that we know what get and set are and what they do, lets look a little more carefully at them:

You may have already noticed that the get portion of the property, just like the set one, also has its own body, delimited by curly brackets (in fact, you will notice that quite a lot of programming concepts in C# use this concept of body delimited by curly brackets).

Now, inside the body of our get portion of the property, we have

The return keyword is not new, we have already learned about it. It immediately stops the execution inside that body, and returns a value provided to it. The this keyword on the other hand, is completely new to us. As with a lot of lessons on this website, I cannot fully explain it yet, because it relies on concepts I haven’t yet explained. But, on a very short notice, you should know that when we are creating a class – such as our Oven class, we are actually creating a blueprint. Whenever we will actually start using Oven objects, we will not use and modify the blueprint itself, instead we will create copies of our blueprint called instances. This is the same for the real world: an ovens factory will never sell the prototype of an oven itself, it will actually create copies of it, which can be sold. This is why we are using the this keyword to indicate that we are referring not to the blueprint itself, but to the actual copy (instance) of the blueprint that we are using at that particular moment. As an example, if we would create 100 instances of our oven object, and we would have this code:

then the this keyword inside the set portion of the Model property of our Oven class would refer to that particular copy of our oven object, the 37th copy, NOT the original blueprint. So, whenever we are using this keyword, the compiler understands that we mean the copy we are currently manipulating, not the unique original.

To completely understand the use of the fields, and their role in creating properties, you should know that a property does not mandatory require a field. We could have declared our properties like this:

or the shortened version of it, which only occupies one line:

The above way of declaring a property is what programmers called an auto implemented property or automatic property.
Now, suppose we just created our 100 oven object copies, and we want to display their weight on the console:

Though some of you would expect the above line of code to generate a compiler error (Use of unassigned variable), because the property doesn’t have a value to return, that is not actually true. Internally, C# will automatically generate a field for our property, which is initialized with the default type value. In our case, the default value for int being 0, the above line of code will display 0 on the console, even if we never assigned the 0 value anywhere in our property. So, this rises the logical question: if C# creates automatic fields for our properties, why should we specifically declare fields anyway? Why not let it be done automatically? There are a few reasons why we need to specify fields explicitly, most of them belonging to rather advanced programming techniques (such as immutability, etc). But for our beginner level of programming, lets consider the following example:

Now, if we create a copy of our Employee class blueprint, we can do this:

Have you ever seen an employee of 200 years old age? I haven’t… So, wouldn’t it be great if we could somehow “force” our Age property to only accept a certain range of values? This is where fields come handy:

Now, we have provided additional logic to our property, and you will never see an Employee object with an age of -5. This would have not been possible if we would have used auto-implemented properties (yes, I know, we haven’t learned about throwing exceptions yet, just use it as it is for the moment).

In conclusion, use auto-implemented properties where you have to simply store some property that does not require any additional logic, and fully qualified properties when such thing is required.

Speaking of setters, they have lower priority than returning a literal in the getter. For instance, the following code makes perfect sense:

but the setter of the property is kind of pointless, since the property will always return 10, no matter how much we try to set a new value.

One other important feature of properties is that they can be read only. In a way, you could say that even the above code sample is read-only, since it would return the same value anyway, regardless of us trying to set a different value. But, however, that is not the usual way of declaring a read only property. Instead, we do it like this:

Whenever you would try to set a value to the above property, you will get a compiler error: Property or indexer ‘Oven.MyProperty’ cannot be assigned to — it is read only.

So, what is the use of a property to which we cannot even assign a default value? Yes, we could use a field variable to set a default value, like this:

but that would defeat the purpose of using auto-implemented properties, wouldn’t it? For this case, we actually have the following solution:

In the above code, we have an auto-implemented property which has a private setter, which means that we can only set its value from within the class declaring the property. Hence, we are allowed to do this:

but we are forbidden to do this:

This is because a private setter only allows us to set a value to the property from within the body of that class, and not from the outside world. We cannot set a value to that property when we create a copy of our Oven object.

Starting with C# version 5.0, there is also a special notation for read only properties, namely this one:

but I’ve rarely seen it used. However, if you like it, go ahead, no one stops you.

Of course, we also have write-only properties, but they are used extremely rarely. Can you even think of an example where you only need to set some data, but never read it?

Tags: , ,

Leave a Reply



Follow the white rabbit