Get and Set property accessors are ‘actually’ methods
- by nmarun
Well, they are ‘special’ methods, but they indeed are methods. See the class below: 1: public class Person
2: {
3: private string _name;
4:
5: public string Name
6: {
7: get
8: {
9: return _name;
10: }
11: set
12: {
13: if (value == "aaa")
14: {
15: throw new ArgumentException("Invalid Name");
16: }
17: _name = value;
18: }
19: }
20:
21: public void Save()
22: {
23: Console.WriteLine("Saving...");
24: }
25: }
Ok, so a class with a field, a property with the get and set accessors and a method. Now my calling code says:
1: static void Main()
2: {
3: try
4: {
5: Person person1 = new Person
6: {
7: Name = "aaa",
8: };
9:
10: }
11: catch (Exception ex)
12: {
13: Console.WriteLine(ex.Message);
14: Console.WriteLine(ex.StackTrace);
15: Console.WriteLine("--------------------");
16: }
17: }
When the code is run, you’ll get the following exception message displayed:
Now, you see the first line of the stack trace where it says that the exception was thrown in the method set_Name(String value). Wait a minute, we have not declared any method with that name in our Person class. Oh no, we actually have. When you create a property, this is what happens behind the screen. The CLR creates two methods for each get and set property accessor.
Let’s look at the signature once again:
set_Name(String value)
This also tells you where the ‘value’ keyword comes from in our set property accessor. You’re actually wiring up a method parameter to a field.
1: set
2: {
3: if (value == "aaa")
4: {
5: throw new ArgumentException("Invalid Name");
6: }
7: _name = value;
8: }
Digging deeper on this, I ran the ILDasm tool and this is what I see:
We see the ‘free’ constructor (named .ctor) that the compiler gives us, the _name field, the Name property and the Save method. We also see the get_Name and set_Name methods. In order to compare the Save and the set_Name methods, I double-clicked on the two methods and this is what I see:
The ‘.method’ keyword tells that both Save and set_Name are both methods (no guessing there!). Seeing the set_Name method as a public method did kinda surprise me. So I said, why can’t I do a person1.set_Name(“abc”) since it is declared as public.
This cannot be done because the get_Name and set_Name methods have an extra attribute called ‘specialname’. This attribute is used to identify an IL (Intermediate Language) token that can be treated with special care by the .net language. So the thumb-rule is that any method with the ‘specialname’ attribute cannot be generally called / invoked by the user (a simple test using intellisense proves this). Their functionality is exposed through other ways. In our case, this is done through the property itself. The same concept gets extended to constructors as well making them special methods too.
These so-called ‘special’ methods can be identified through reflection.
1: static void ReflectOnPerson()
2: {
3: Type personType = typeof(Person);
4:
5: MethodInfo[] methods = personType.GetMethods();
6:
7: for (int i = 0; i < methods.Length; i++)
8: {
9: Console.Write("Method: {0}", methods[i].Name);
10: // Determine whether or not each method is a special name.
11: if (methods[i].IsSpecialName)
12: {
13: Console.Write(" has 'SpecialName' attribute");
14: }
15: Console.WriteLine();
16: }
17: }
Line 11 shows the ‘IsSpecialName’ boolean property. So a method with a ‘specialname’ attribute gets mapped to the IsSpecialName property. The output is displayed as:
Wuhuuu! There they are.. our special guests / methods.
Verdict: Getting to know the internals… helps!