.NET Spider

Tuesday, January 13, 2009

A DISSERTATION ON .NET PROPERTIES

I’ve been meaning to write this piece for quite some time. Today we’re going to discuss properties in general, and specifically what are referred to as “trivial” properties.

The Technology Behind Properties
Chances are you can skip this part if you have any .NET development experience.

Properties are specially-demarcated methods in a given .NET class. When your class is used by another piece of code, the property looks and acts much like a field or variable.

Let’s examine a snippet of code:

public class Class1
{
    public int PublicValue;

    private int myValue;
    public int Value
    {
        get { return myValue; }
        set { myValue = value; }
    }
}
In this code, we define a very simple class. This class has one public “field” and one public “property.” The property defines a “getter” and “setter” for its data. When using this class, we might use code such as:

public static void Main()
{
    Class1 c = new Class1();
    c.PublicValue = 5;
    c.Value = 10;
}
So from the client programmer’s perspective, a public field and a public property more-or-less look the same. What’s the difference “under the hood?”

If you use ILDASM (the Intermediate Language Disassembler, which ships with the .NET Software Development Kit), you will see the following fields (cyan rectangle) of Class1:

PublicValue : public int32
myValue : private int32
You’ll see the following methods (purple rectangles):

.ctor : void()
get_Value : int32()
set_Value : void(int32)
And the following property definition:

.property instance int32 Value()
The property definition ties the two get/set methods together as a property for .NET languages. You can see this if you look at the MSIL definition of the property:

.property instance int32 Value()
{
  .get instance int32 DemoClasses.Class1::get_Value()
  .set instance void DemoClasses.Class1::set_Value(int32)
} // end of property Class1::Value
OK, so what does writing the extra code for a property actually buy you? You have the ability to add logic to the property, to ensure business rules are followed. You can also use it, on reference types, to ensure that no null values are returned.

Also, if you want to use object binding, you have to use properties – you can’t use public fields for binding.

Designing Properties
So now you know the basics of how properties work. What are some basic guidelines?

I believe that properties exist to make your life, and the lives of the client developers using your class, easier. To this end, here are John’s Simple Rules of Properties:

Properties shall never return null, unless there is a damn good reason to do so. If your property has to return null for some reason, then document it – use the documentation feature of C# or VB to do so.
Generally, properties should enforce business rules. If you have a numeric value with logical minimums and maximums, enforce them. If the string must have a certain length, enforce that. It’s OK to throw exceptions from the set block, or – if applicable – modify the value accordingly (truncation, etc). However, document any and all side effects which are possible.
Trivial Properties
Which brings us to “trivial” properties. Trivial properties are ones such as that which we wrote above – there’s no logic, no nothing, the get simply returns whatever value is in the backing store and the set simply sets the backing store.

I am generally against trivial properties. I’m not against writing the code, but I am against using a property without taking advantage of its benefits.

Automatic Properties
Starting with Visual Studio 2008 and .NET 3.0, C# provides the concept of “automatic” properties. “Automatic” properties look something like this:

public class Class1
{
    public int Value
    {
        get;
        set;
    }
    public string Text
    {
        get;
        set;
    }
}
Notice that we wrote almost no code there. When we compile, the compiler will generate the full property for us. Let’s see what the disassembly looks like.

First there are the fields. We didn’t define any in our class, but we have some:

k__BackingField : private string
k__BackingField : private int32
These are the backing stores for the properties. As for the property methods themselves:

get_Text : string()
get_Value : int32()
set_Text : void(string)
set_Value : void(int32)
And finally the properties themselves:

Text : instancestring()
Value : instance int32()
That’s all well and good, but what do these properties actually do? Well, simply put, .NET’s automatic properties create “trivial” properties – the bare minimal get/set blocks. Running the code through ILDASM, here’s the output for the Text property:

.method public hidebysig specialname instance string 
        get_Text() cil managed
{
  .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) 
  // Code size       7 (0x7)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  ldfld      string DemoClasses.Class1::'k__BackingField'
  IL_0006:  ret
} // end of method Class1::get_Text
.method public hidebysig specialname instance void 
        set_Text(string 'value') cil managed
{
  .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) 
  // Code size       8 (0x8)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  ldarg.1
  IL_0002:  stfld      string DemoClasses.Class1::'k__BackingField'
  IL_0007:  ret
} // end of method Class1::set_Text
Looking at the MSIL, they do nothing but set and return the backing store. There is no logic, no null checks, no nothing. We can confirm this by running the entire class through Reflector. (Every .NET developer should have Reflector installed.) Here’s the output:

public string Text
{
    [CompilerGenerated]
    get
    {
        return this.k__BackingField;
    }
    [CompilerGenerated]
    set
    {
        this.k__BackingField = value;
    }
}
When using this class, therefore, it’s entirely possible to have null returned – so the client developer potentially has to do null checks to avoid NullReferenceExceptions. This violate’s John’s First Rule of Properties.

Conclusion
So in conclusion, properties in general are good and useful, but only if you’re using them effectively. Automatic properties are, in my mind, to be avoided as they generate trivial properties.






1 Comments:

At January 17, 2009 7:32 AM , Blogger Zephyr Girl said...

Hi Friend,
ur post is informative....
i like it....
visit mine, i have added few more posts...
Thanks,
zephyr girl

 

Post a Comment

Subscribe to Post Comments [Atom]

<< Home