Initialising static fields in classes inheriting from BusinessBase

Initialising static fields in classes inheriting from BusinessBase

Old forum URL: forums.lhotka.net/forums/t/7544.aspx


sturdytree1 posted on Monday, August 31, 2009

I've read page 248/249 of Business Objects 2008 and am puzzled by a couple of things, and will be grateful to anyone who can 'unpuzzle' me!

Rocky states that where a class inherits from a base class that in turn inherits from a csla base class (such as Businessbase), then there is an issue to consider (though V 3.6.1 has now fixed this).

The issue was that the timing of static field initialisation was uncertain, and so in a typical field/property such as:

private static PropertyInfo NameProperty = RegisterProperty(new PropertyInfo("Name","Name"));
public string Name
{
get { return GetProperty(NameProperty); }
}
set { SetProperty(NameProperty, value); }
}

there is a danger the Name property is accessed before the static NameProperty is initialised (and RegisterProperty processed). In such a case GetProperty/SetProperty will fail as they will not find NameProperty in FieldManager.

But, if that scenario does happen, will not the very act of running, say 'SetProperty(NameProperty, value)' reference the static NameProperty, thus causing all static fields to be initialised before the SetProperty code is run? Clearly this does not happen, but I'm not sure why?

Also, Rocky mentions in his book the above is not a problem for a class inheriting directly from a csla base class (direct case), but only where a class inherits from a custom base that in turn inherits from a csla base (indirect case). Why should this matter, as even with a direct case you could access an instance property before the static fields are initialised?

The following is an old post that deals with this issue, but does not seem to shed light on the above:

http://forums.lhotka.net/forums/1/26436/ShowThread.aspx

RockfordLhotka replied on Monday, August 31, 2009

It is because of the way .NET initializes static fields. They are initialized per class not per object.

So if you have an inheritance hierarchy of A<-B<-C and touch a static member defined in A and C that'd force all static fields in A and C to be initialized, but not in B.

Yes, I know that your object is an instance of C (and thus A and B), but the static fields are initialized per class, so the fields defined in A, B and C are all initialized separately.

When you call SetProperty() on a field defined in C you force initialization of all C fields. And SetProperty() uses static members in BusinessBase<T>, which forces initialization of the CSLA base class. But if you have an intermediate class inbetween, nothing forces initialization at that level.

sturdytree1 replied on Monday, August 31, 2009

Rocky,

Thanks for the response.

I do understand the static fields are initialised per class (and not per object or per inheritance hierarchy), but if we take the specific case:

class MyBase: BusinessBase
{ // no code }

class Customer : MyBase
{
//NameProperty as defined in earlier post
}

then, if I wrote:

Customer c = new Customer:
string name = c.Name;

That would cause GetProperty(NameProperty) to run. When the Runtime references the NameProperty, why would that not cause the static NameProperty that belongs to Customer to be initialised? If it does, then the property will be registered before GetProperty runs, avoiding any problems. Sorry if I'm missing something obvious.

If I had

class Customer: BusinessBase
{
//NameProperty as defined in earlier post
}

Why would this not cause a problem, as there would still be the possibilty that the instance property Name is accessed before the static field is intiialised?

RockfordLhotka replied on Monday, August 31, 2009

With CSLA there's also the n-tier aspect.

If your DataPortal_XYZ or object factory methods are running on the app
server, then your LoadProperty() or SetProperty() calls would occur on the
server, initializing the static fields on the server.

The object instance is then serialized to the client, where the object graph
rehydrates without invoking any static members at all. So (unless something
else occurs) the static fields are uninitialized until your GetProperty()
call.

Rocky

sturdytree1 replied on Monday, August 31, 2009

Thanks again, but

1) would you agree that in my example above there would equally be a problem where Customer inherits directly from Businessbase? If not, then I'll really be grateful if you could indicate why (I'm only asking so I can understand your statement in the Business Objects book that the problem does not arise on a direct inheritance).

2) What is the flaw (and there obviously is one!) in my argument on there apparantly not being a problem if the NameProperty reference in Set/Get causes the static intiialisation. If the answer is it does not cause the initialisation, do we know why not?

RockfordLhotka replied on Monday, August 31, 2009

I'm afraid I don't have time to re-hash all that in my mind to form a
complete description of .NET's behavior.

Brad Abrams wrote a blog post a couple years ago where he carefully walked
through how static fields are initialized in .NET. This was my starting
point (once I realized I had a problem).

I then wrote numerous test apps with various static field combinations and
used them in one AppDomain and serialized across AppDomains to study the
behavior. This was necessary because Brad didn't discuss serialization in
the blog post.

I then thought I had it, until someone (Joe I think?) pointed out the
problem with intermediate classes in the inheritance hierarchy, which is
very real. The _forceInit technique solves the problem.

But this was a major pain point as 3.5 rolled out, which is why 3.6
introduces a more automated solution, using reflection to touch one static
field per class, once per type per AppDomain. The cost is low, and the
benefit is incredibly high.

Rocky

sturdytree1 replied on Monday, August 31, 2009

Great, thanks Rocky.

Your time on this is much appreciated.

Copyright (c) Marimer LLC