LA.NET [EN]

Sep 17

Properties on C#

Posted in C#      6 Comments »

Properties are strange beasts…in fact, when you access a property, you”re really calling a method. Let”s start with a simple example that shows a “parameterless property”:

public class Person
{
    public String Name;
    private String _address;

    public String Address
    {
        get { return _address; }
        set { _address = value; }
    }
}

The Person class has two fields: Name and _address with different access modifiers applied to them. What this means is that you can access the Name field directly, but you must go through the Address property if you want to get or set the value of the _address field. Here”s some code that shows how you can use the field and the method from C# code:

Person p = new Person();
p.Name = “Luis”;
p.Address = “Funchal, Madeira”;

When you compare both approaches, they really do look similar. However, when you”re setting the address, you”re really calling a method, as the following IL for the last line of the previous code shows:

L_0013: ldstr “Funchal, Madeira”
L_0018: callvirt instance void Livro.Person::set_Address(string)

If you”re thinking “where does the set_Address method comes from?” then the answer is simple: the C# compiler generates 2 methods by prefixing the property name with get_/set_ prefixes. Here”s the IL code for the Address property:

.property instance string Address
{
    .get instance string Livro.Person::get_Address()
    .set instance void Livro.Person::set_Address(string)
}

The previous snippet also shows an interesting thing: the C# compiler groups the get_Address and set_Address methods and annotates them with the .property instruction on the metadata of the class. This info is used by compilers and IDEs making you believe that you”re using properties. However, the CLR does not use this info and will always call one of the methods you”ve defined (as you”ve seen in one of the previous snippets).

One interesting thing about properties (which most people don”t know) is that you can have different access modifiers applied to the get and set methods. For instance, the following definition of the Address property makes the set method available only to types defined in the same assembly as the Person type (or in “external” types defined in an assembly that has been passed to the InternalsVisibleToAttribute):

public string Address
{
   get { return _address; }
   internal set { _address = value; }
}

As I”ve said,the type of property presented in the previous is know as “parameterless property” because you don”t pass any properties to the get/set methods when you call them. C# will also let you define properties that let you pass parameters to its get/set methods. In C#,these properties are called indexers and they”re exposed through an array-like syntax (you need to use the [] operator). Here”s a quick example of how you can define and use this kind of property:

 public class CustomArray
{
    private Int32[] _arr = new Int32[10];

    public Int32 this[Int32 pos]
    {
        get
        {
            return _arr[pos];
        }
        set
        {
            _arr[pos] = value;
        }
    }
}

The next snippet shows how to use indexed property from C# code:

CustomArray ar = new CustomArray();
ar[0] = 10;
Console.WriteLine(ar[0]);

If you”ve been following along, then the IL generated by the C# compiler shouldn”t really look weird:

.property instance int32 Item
{
    .get instance int32 Livro.CustomArray::get_Item(int32)
    .set instance void Livro.CustomArray::set_Item(int32, int32)
}

The main difference is that there”s an aditional parameter passed to the get/set methods that are automatically generated by the compiler. There”s one thing that might be bothering you: why aren”t the IL methods named get_this and set_this? After all, you”ve used the reserved this term for the property name, right? I thought about this too and Richter”s excellent CLR via C# book has the best explanation i”ve see on the subject. According to Jeffrey, the name”s choice was necessary because you cannot name the indexed properties you build in C#. That”s why all the classes that have an indexer have a property called Item. btw, you can change this default name by annotating the indexer with the IndexerNameAttribute attribute. One more thing: the this identifier was chosen so that you can only define indexers on instances of objects. Currently, C# does not offer you any chance of defining static indexers.

by now, you”ve already seen most of the important things you should know about properties. Properties are really important in some scenarios. For instance, if you need to perform some sort of validation when setting the value of a field, then using a property will let you do that without sacrificing the syntax you”re already accustomed to. Another good example where properties are necessary is binding in Windows forms.

However, it”s really important to always keep in mind that properties are really methods and that there are certain things you can do with fields but cannot do with them. For instance, you cannot pass a property as a ref or out parameter (Mike Stall has a good post on this subject). Another thing that might surprise you is that properties aren”t “side-effect free”. When you access a field, it will always return its content. If you don”t change it, that means that you”ll always get the same value. That might not be the case with properties. For instance, take a look at the following property:

public DateTime MyDate
{

   get { return DateTime.Now; } //the value of this property is never the same
}

Even though there are some people that say that porperties aren”t really that good, I must say that I”m not against its use if you do keep in  mind that they”re really methods…

6 comments so far

  1. vikram
    5:00 am - 9-18-2007

    Good one…..

  2. Kant
    3:24 pm - 10-9-2007

    Easy to follow the concept. Thank you

  3. bad credit loans
    11:47 pm - 12-29-2009

    Hello!!! msmvps.com is one of the best resourceful websites of its kind. I enjoy reading it every day. msmvps.com rocks!