Rockford Lhotka
    CTO at Magenic
    Author, speaker, software architect
    Creator of the CSLA .NET framework

Home
Blog
CSLA .NET
Magenic
Speaking
Publications
About me
Contact me

Login

CSLA .NET 3.5 managed fields and inheritance

 

CSLA .NET 3.5 implements a powerful new way of implementing properties, where you don't need to declare a field to store the property's value. The field values are managed by CSLA .NET and so are called managed fields. The syntax for declaring such a property is shown here, along with syntax for the use of private fields and the older 2.0/3.0 technique.

If you use managed fields or private fields you must call RegisterProperty() to register your PropertyInfo objects with CSLA .NET. This becomes a little more complex if you are declaring some properties in a base class and then using inheritance to create subclasses that also declare their own properties. In this case, the base class properties are declared as part of the base class and use the base class type:

[VB]

Private Shared NameProperty As PropertyInfo(Of String) = _
  RegisterProperty(Of String)(GetType(BaseType(Of T)), New PropertyInfo(Of String)("Name"))

Public Property Name() As String
  Get
    Return GetProperty(Of String)(NameProperty)
  End Get
  Set(ByVal value As String)
    SetProperty(Of String)(NameProperty, value)
  End Set
End Property

[C#]

private static PropertyInfo<string> NameProperty =
  RegisterProperty<string>(typeof(BaseType<T>), new PropertyInfo<string>("Name"));

public string Name
{
  get { return GetProperty<string>(NameProperty); }
  set { SetProperty<string>(NameProperty, value); }
}

The rule is simple: when calling RegisterProperty(), pass in the type of the containing class, whether that be the base class or a subclass.

But in a base class there's one other step that is critical. It turns out that .NET doesn't guarantee that Shared/static fields are initialized before instance code runs in your object. Click here for more details.

This means that it is possible for the RegisterProperty() calls in the base class to be called too late in the object initialization process. The result will be unregistered PropertyInfo objects, which will result in runtime exceptions (probably a null reference exception).

The solution is to force the Shared/static fields in the base class to be initialized before they are needed. There are two ways to do this:

  1. Declare a Shared/static constructor in the base class. Even if empty, its very existence will force the fields to initialize. Please note that there is a performance penalty for implementing a Shared/static constructor.
  2. "Touch" a Shared/static field in the instance constructor of the base class. Accessing a Shared/static field in a type forces all Shared/static fields of that type to initialize.

Though option 2 seems like a hack, it appears to be the most performant way to guarantee proper initialization of Shared/static fields. To implement this option add code like this to your base class:

[VB]

Private Shared _dummy As Integer

Protected Sub New()
  _dummy = 0
End Sub

[C#]

private static int _dummy;

public ObjectType()
{
  _dummy = 0;
}

To implement the Shared/static constructor add code like this:

[VB]

Protected Shared Sub New()
End Sub

[C#]

static ObjectType()
{ }

Either technique works, and you must implement one technique or the other or your application will fail at runtime.

 

(Updated 1/29/2008)