Behind the Scenes Look at C#: Properties

Without properties you define your fields as public (not private). By doing that, you give client code access to the fields and allow it to modify the values as much as they want. In this article we will discuss coding techniques without properties, with properties, and more.

Contributed by
Rating: 5 stars5 stars5 stars5 stars5 stars / 14
July 13, 2005
Rate this Article:
MEH MEH++


SEARCH ASP FREE
TOOLS YOU CAN USE

advertisement

The Public Fields Example

In the previous articles we have used public fields to store values, but this is not a good Object Oriented Programming practice. Let's see why. Compile the following code and run it:

using System;
namespace Properties
{
class Class1
{
static void Main(string[] args)
{
// this code is fine
Worker worker1 = new Worker();
worker1.FirstName = "Michael";
worker1.LastName = "Youssef";
worker1.Department = "IT";
worker1.Age = 22;

// this code is not fine
Worker worker2 = new Worker();
worker2.FirstName = "Steve";
worker2.LastName = "John";
worker2.Department = "NONE";
worker2.Age = 900;

Console.WriteLine(worker1);
Console.WriteLine(worker2);
Console.ReadLine();
}
}

public class Worker
{
public string FirstName;
public string LastName;
public string Department;
public int Age;

public override string ToString()
{
return FirstName +" "+LastName+" is working in "+Department+
" and he's "+Age+" years old";
}

}
}

You will get the following result to the console. Do you like it?

Steven John is working in NONE and he's 900 years old. As you can tell, the object worker2 has invalid data and its state is not maintained. The client code (our Main method) has accessed the public fields of the object and assigned values to the fields which yield us this mess.

We need a way to secure our data, so the first thing that comes to our mind is to declare these fields as private and use methods to set and get the values. Using this technique, we can write code to check the user input (suppose that the value 900 has been input from the user) and accept only the data that is valid to the object and to our business rules. For example, you have a business rule that states that the worker age must be less than 40 years old on the day of hiring, and you have another rule that states that the worker nationality is American because you don't hire international workers, and so on.

The method that returns or gets the value of the private field is called a get method. By convention programmers used to call it a get accessor because this method has access to a private field, and it's the only way to get this private field's value. The method that sets or assigns a value to private fields is called a set method. Programmers used to call it a set accessor because it has code that sets a value to the private field, and maybe after some validation code, checks that the data is valid for this field.

By convention, programmers used to name the get methods with the prefix "Get." If you have a private field called firstName, it's better to call the get method GetFirstName(). The same holds true with the set methods, so the set method for the firstName field is SetFirstName() and so on. 

Let's modify the above example to secure the object's fields.

The Private Fields Example

The following application contains the updated version of the class Worker, which defines the get and set methods and modifies the the fields to be private, not public. The code contains a new C# keyword called throw, which is used to throw a new exception object. I will talk about exceptions in this series; I know that many of you know about them. Anyway, for those of you who don't know what an exception is, think of it as a new way to say "I have some error with my code and it needs to be handled." Copy the following code and run it:

using System;
namespace Properties
{
class Class1
{
static void Main(string[] args)
{
try
{
Worker worker1 = new Worker();
Console.WriteLine("Enter Your First Name");
worker1.SetFirstName(Console.ReadLine());
Console.WriteLine("Enter Your Last Name");
worker1.SetLastName(Console.ReadLine());
Console.WriteLine("Enter Your Department");
worker1.SetDepartment(Console.ReadLine());
Console.WriteLine("Enter Your Age");
worker1.SetAge(Convert.ToInt32(Console.ReadLine()));

Console.WriteLine(worker1);
Console.ReadLine();
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
Console.ReadLine();
}
}
}

public class Worker
{
private string firstName;
private string lastName;
private string department;
private int age;

// writing the get methods
public string GetFirstName()
{
return this.firstName;
}

public string GetLastName()
{
return this.lastName;
}

public string GetDepartment()
{
return this.department;
}

public int GetAge()
{
return this.age;
}

// writing the set methods
public void SetFirstName(string firstName)
{
if(firstName == String.Empty)
{
throw new ArgumentNullException();
}
else
{
this.firstName = firstName;
}
}

public void SetLastName(string lastName)
{
if(lastName == String.Empty)
{
throw new ArgumentNullException();
}
else
{
this.lastName = lastName;
}
}

public void SetDepartment(string dept)
{
switch(dept)
{
case "IT":
this.department = "IT";
break;
case "HR":
this.department = "HR";
break;
case "Sales":
this.department = "Sales";
break;
default:
throw new ArgumentException("invalid department");
}
}

public void SetAge(int age)
{
if(age > 18 && age < 40)
{
this.age = age;
}
else
{
throw new ArgumentException("The worker can't be over 40");
}
}

public override string ToString()
{
return firstName +" "+lastName+" is working in "+department+
" and he's "+age+" years old";
}

}
}

Enter whatever values you like for the first name, last name and department, but enter 1000 for the age and see what will happen.

The object has not been created, and the application has printed to the console window "The worker can't be over 40", which is our business rule for this example. The Worker class has been modified. The fields are now private instead of public, so the client code has no access or visibility to these fields. Take a look at the IntelliSense feature of VS.NET when we try to access worker1 object members:

You don't see the private fields and you don't have direct access to them. You set and get their values through the Getxxx methods and Setxxx methods you see in the list. The syntax of the Get methods is very simple: you declare the method public and define the return data type as the same as the field. The Set methods can be as complex as you want, because you may validate data and do other operations, such as throw an exception in case the data is invalid. 

We have done this in the example. In the method SetFirstName we wrote code to test on the assigned value. If it's equal to String.Empty (that means that it doesn't contain any characters), an exception of type ArgumentNullException will be thrown. Try it yourself. Press the Enter key without typing any characters to the First Name and the application will print to the Console Window "value can't be null". The same code works for the SetLastName method.

The SetDepartment method uses a switch case statement to assign the value of the worker department. In case of an invalid department entry, the default section will be executed, which will throw the exception ArgumentException. The SetAge method tests that the value assigned is greater than 18 and less than 40. If it's not, the else block executes, which throws the exception ArgumentException too.

As you can see, we have control over the values that will be assigned to the private fields. We throw exceptions to stop the object creation process. Actually the code is more complex than our example when you use database, ADO.NET and Windows Forms.

The Main method creates an object of type Worker and gets the values from the user. Note that we are not using the assignment operator as with the public fields example to assign the values to the fields, but we are passing the values (that return from the method Console.ReadLine()) as method arguments. All of the statements are enclosed in a try/catch block, which will be discussed in detail with exceptions. For now think of the try block as a block of statements that can throw an exception, and the catch block as containing code to catch and handle the exception. In the Catch block we simply write the exception.Message (the message error) and wait for the user to press the Enter key using the Console.ReadLine() method.

This code is fine and does exactly what we need, but as you can see there are some differences between using fields and methods that handle fields. For example, we can't use the assignment operator with the get/set methods like we do with the fields. The redundant methods declaration to get and set the values of the fields also makes the code look ugly. We need a way to simulate the field behavior while we still use the power of methods we have seen, and C# features a construction called property to solve our problem. Let's meet our new class member.

C# Properties

As you know, accessing public fields from the client code can be very dangerous, and programmers used to define get and set methods to have access to private fields. C# defines a construction called a property, which has been designed to have access to the private field. There are two ways to look at a property of a class.

The first way is to look at the property as an attribute of the class, like the class Employee which can define a property called FirstName, and another one called Age; the list is not limited. So instead of considering the fields as the class attributes, we will declare them as private fields and declare the properties as public to have indirect access to the fields. The other way to look at properties is from the MSIL code. When you define a property in your class, the C# compiler generates two methods, which are a get method and a set method to form the property, as we will see shortly.

You access the property in the same way as you access the field, and you assign values to the property in the same way you assign values to the fields (using the assignment operators). You can think of the property as a public representation of your private field, and deal with it on that basis. The following code is the syntax for writing a property:

public class Customer
{
private string firstName;

public string FirstName
{
get
{
return this.firstName;
}

set
{
this.firstName = value;
}
}
}

The class Customer defines the private field firstName of type string and defines a public property that represents the field. In other words, it defines a property to access the field. As you can see, the property declaration consists of an access modifier followed by the data type of the property (which must be the same as the field), followed by the name of the property. Note that we don't use parentheses with properties, because we don't pass any parameters. The property defines a get accessor that returns the value of the private fields (which is much more like our Getxxx method), and defines a set accessor that assigns a value to the private field.

The very interesting part here is when the get and set accessors are called. When you write an expression like aCustomer.FirstName = "Michael" the C# compiler understands that you need to assign this value, calls the set part of the property, and passes this value "Michael" to it. Note that inside the set accessor you refer to the assigned value using the keyword value. When you write an expression like Console.WriteLine(ac.FirstName), the C# compiler understands that you need to get (or read) the private field value, so it calls the get part of the property.

When you write a property that contains only the get accessor, you are defining a Read-Only property. The .NET Framework Classes define many Read-Only property, like the one that we just met in the above application: the Exception.Message property is a Read-Only property that gets a message representing the exception object. This is very useful, because sometimes you need to disallow the assignment to the property.

When you declare a property only with the set accessor, you are defining a Write-Only accessor. It's not very common to do so; anyway, it exists, and who knows? You may find a scenario that uses a Write-Only accessor; maybe you have a highly secure system that doesn't have a "forget your password" process because it defines the Password property as Write-Only.

The Customer class contains (actually it must contain) a private field to store the value that will be set by and get by the property. Note that we have used the Pascal Naming Convention to name the property FirstName and the camel Naming Convention to name the private field firstName, because C# is case sensitive and both the C# compiler and the Runtime know that firstName is not the same as FirstName. So inside the class Customer we can use the identifier firstName to the private field, and outside the class we use the property name (the public name of the field) FirstName. This is perfect to express what we are talking about when we say "a public name of the field". Most of the time you will define your properties as public, but many times you will define some of them as protected, so the derived classes can access them but the client code can't. You can define a property as private, but it's very uncommon to do so.

The following is the client code that access (set and get) the property.

{
Customer ac = new Customer();
ac.FirstName = "Michael";
Console.WriteLine(ac.FirstName);
}

As you can see, the client code has no access to the field firstName, and the access to the field can only happen through the FirstName property. Here we use the same coding technique as we have used with the public fields example; we assign the value through the assignment operator. The coding technique of the Getxxx/Setxxx methods is not perfect because of the passing of the values to the methods. The assignment technique makes you feel like you are assigning to the field itself.

Modifying the Worker Class

Let's modify our Worker class to utilize properties instead of the Getxxx/Setxxx methods.

using System;
namespace Properties
{
class Class1
{
static void Main(string[] args)
{
try
{
Worker worker1 = new Worker();
Console.WriteLine("Enter Your First Name");
worker1.FirstName = Console.ReadLine();
Console.WriteLine("Enter Your Last Name");
worker1.LastName = Console.ReadLine();
Console.WriteLine("Enter Your Department");
worker1.Department = Console.ReadLine();
Console.WriteLine("Enter Your Age");
worker1.Age = Convert.ToInt32(Console.ReadLine());

Console.WriteLine(worker1);
Console.ReadLine();
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
Console.ReadLine();
}
}
}

public class Worker
{
private string firstName;
private string lastName;
private string department;
private int age;


public string FirstName
{
get
{
return this.firstName;
}

set
{
if(value == String.Empty)
{
throw new ArgumentNullException();
}
else
{
this.firstName = value;
}
}
}

public string LastName
{
get
{
return this.lastName;
}

set
{
if(value == String.Empty)
{
throw new ArgumentNullException();
}
else
{
this.lastName = value;
}
}
}

public string Department
{
get
{
return this.department;
}

set
{
switch(value)
{
case "IT":
this.department = "IT";
break;
case "HR":
this.department = "HR";
break;
case "Sales":
this.department = "Sales";
break;
default:
throw new ArgumentException("invalid department");
}
}
}

public int Age
{
get
{
return this.age;
}

set
{
if(value > 18 && value < 40)
{
this.age = value;
}
else
{
throw new ArgumentException("The worker can't be over 40");
}
}
}

public override string ToString()
{
return firstName +" "+lastName+" is working in "+department+
" and he's "+age+" years old";
}

}
}

The result of running this code will be the same:

As you can see, we still do our data validation and throw exceptions from inside the set part of the properties. Let's take a look at the MSIL of this application. Load the file with the Ildasm.exe and navigate to the class Worker.

get_Age, get_Department and set_Age and set_Department? Yes, the C# compiler generates those methods as the Getxxx and Setxxx methods. In the next part of this article, we will discuss the MSIL Generated code of C# Properties, static properties, read-only properties and more. 

blog comments powered by Disqus
C# ARTICLES

- Beginning C#
- ASP.NET RedirectPermanent Method using C# an...
- C Programming Language and UNIX Pioneer Pass...
- Using Facebook JavaScript SDK in ASP.NET wit...
- ASP.NET Export to Excel and Word using VB.NE...
- WAV and MP3 Streaming with ASP.Net and C#
- Game Programming using SDL: the File I/O API
- C# and Java Developer Jobs on the Rise
- The Future Evolution of C# and VB.NET
- C# If and Else-if Statements
- How To Use the C# String Replace Method
- 5 Ways to Parse XML in C#
- C# Meets Design Patterns
- Coding a CRC-Generating Algorithm in C
- Cyclic Redundancy Check

ASP Web Hosting ASP.Net Web Hosting Windows Web Hosting
ASP Free Forums 
 RSS  Tutorials RSS
 RSS  Forums RSS
 RSS  All Feeds
Site Map 
Request Media Kit
Write For Us Get Paid 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
Privacy Policy 
Support 


© 2003-2012 by Developer Shed. All rights reserved. DS Cluster 8 - Follow our Sitemap
Most Popular Topics
All ASP.Net Tutorials