Inherited property is not registered?

Inherited property is not registered?

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


tchimev posted on Friday, September 19, 2008

I want to inherit Csla BusinessBase object.
In my parent object I declare an ID property.
When I create derived object there is no ID property in the object’s FieldManager list.
I found out that RegisterProeprty() method inside base class never called(may be because it is static).

How should I declare properties in the base class?

Here is the example code:

class Program
{
    static void Main(string[] args)
    {
        Company company = Company.NewCompany();
        company.Name = "NewTest";

        //error: "One or more properties are not registered for this type"
        Console.WriteLine(company.ID);
    }
}

public abstract class Party<T> : BusinessBase<T> where T : Party<T>
{
    protected static PropertyInfo<int> _id =
        RegisterProperty<int>(typeof(T), new PropertyInfo<int>("ID"));
    public int ID
    {
        get { return GetProperty<int>(_id); }
    }
}

public class Company : Party<Company>
{
    private static PropertyInfo<string> _name =
        RegisterProperty<string>(new PropertyInfo<string>("Name"));
    public string Name
    {
        get { return GetProperty<string>(_name); }
        set { SetProperty<string>(_name, value); }
    }

    public static Company NewCompany() { return DataPortal.Create<Company>(); }

    private Company() { }
}

stefan replied on Friday, September 19, 2008

Search the forum for recent threads containing '_dummy' or just 'dummy'

Stefan

Fintanv replied on Friday, September 19, 2008

This is the link to the workaround: http://forums.lhotka.net/forums/thread/24472.aspx

RockfordLhotka replied on Friday, September 19, 2008

Just to restate the solution (because this is clearly going to be a common problem):

In every class where you use inheritance from your own base classes you must force all static/Shared fields to initialize. The safest, surest and simplest way to do this is like this:

public class MyClass : MyBaseClass<MyClass>
{
  private static int _forceInit;

  protected MyClass()
  {
    _forceInit = 0;
  }

  protected override OnDeserialized(...)
  {
    _forceInit = 0;
  }
}

The way, when the first instance of the type is created (either directly or through deserialization) all static/Shared fields defined in this class are initialized. You must repeat this pattern in your custom base classes and subclasses.

If you inherit directly from a CSLA base class (like BusinessBase<T>) then you don't need to worry about this issue.

JoeFallon1 replied on Thursday, October 02, 2008

RockfordLhotka:

Just to restate the solution (because this is clearly going to be a common problem):

In every class where you use inheritance from your own base classes you must force all static/Shared fields to initialize. The safest, surest and simplest way to do this is like this:

public class MyClass : MyBaseClass<MyClass>
{
  private static int _forceInit;

  protected MyClass()
  {
    _forceInit = 0;
  }

  protected override OnDeserialized(...)
  {
    _forceInit = 0;
  }
}

The way, when the first instance of the type is created (either directly or through deserialization) all static/Shared fields defined in this class are initialized. You must repeat this pattern in your custom base classes and subclasses.

If you inherit directly from a CSLA base class (like BusinessBase<T>) then you don't need to worry about this issue.

Rocky,

Can you please clarify this for me?

Here is a sample inheritance hierarchy:

1. CSLA BusinessBase

2. My Base Class (Inherits 1)

3. My CodeGen Class (Inherits 2)

4. My DeveloperLevel Class (Inherits 3)

5. My FinalType Class (Inherits 4)

Where do I need to add the static int code?

A. Just 2

B. In 2,3,4 and 5.

C. Some other combination?

Joe

 

RockfordLhotka replied on Thursday, October 02, 2008

You need to insert the _forceInit code in 2-5.

 

Rocky

 

JoeFallon1 replied on Thursday, October 02, 2008

Great. Much clearer.

=========================

Now what about this statement you made:

"If you inherit directly from a CSLA base class (like BusinessBase<T>) then you don't need to worry about this issue."

Assuming this inheritance chain:

1. CSLA BusinessBase

2. My FinalType Class (Inherits 1)

Where do I need to add the static int code?

A. No place (according to your statement)

B. In 2 (why does this not need it when the other inheritance chain needed it on every step?)

Joe

 

 

RockfordLhotka replied on Thursday, October 02, 2008

I’ll try to be as clear as I can J

 

There are exactly two scenarios.

 

1.       Your business class inherits directly from a CSLA base class.

In this case you don’t need to do anything special, your code should just work.

2.       Your business class inherits from a custom base class that inherits from a CSLA base class. This scenario can go n levels deep.

In this case you must include the _forceInit code in EVERY ONE OF YOUR CLASSES in that inheritance hierarchy.

 

If you are using code-gen, I’d just put it in the template and always include the _forceInit code. It doesn’t cause harm, and would simplify template creation.

 

Rocky

chenzd replied on Tuesday, October 21, 2008

Add a static constructor function to Company as following:

static Company()

{

   Party._id = RegisterProperty<int>(typeof(T), new PropertyInfo<int>("ID"));

   _name = RegisterProperty<string>(typeof(Company), new PropertyInfo<string>("Name"));
}

 

The field _propertyList managing registered properties is marked for NonSerializedAttrube,sothey are found after deserialized.

RockfordLhotka replied on Tuesday, October 21, 2008

Unfortunately I’ve run into a scenario where just having a static constructor is not enough to trigger initialization of static fields. I don’t remember the specifics, but it had to do with serializing objects to/from Silverlight, and seems to violate the .NET rules on static field initialization.

 

The _forceInit technique appears to work in all scenarios, and so it is the technique I’m recommending. If you use inheritance, ALL YOUR CLASSES should do this:

 

public class <my class>

{

  private static int _forceInit;

 

  private <my class>()

  {

    _forceInit = 0;

  }

 

  protected override void OnDeserialized(…)

  {

    _forceInit = 0;

  }

}

 

Rocky

 

JoshL replied on Monday, December 15, 2008

Shouldn't the OnDeserialized overload call base.OnDeserialized? I'm thinking it should be declared like this:

protected override void OnDeserialized(System.Runtime.Serialization.StreamingContext context)
{
base.OnDeserialized(context);
_forceInit = 0;
}

JoshL replied on Tuesday, December 16, 2008

For some time I have attempted to use the above solution to work around the "property not registered" error, to no avail. Despite that fact that I had the above code (with the addition of a call to base.OnDeserialized) in each of the classes in my inheritance hierarchy, I would still get the error.

Finally I found the problem, which I think might be a CSLA bug: if SetProperty or LoadProperty is called, no subsequent RegisterProperty calls are honoured! I had the following in a MyBusinessBase class, inherited from CSLA:

private static int _forceInit;
private static int lastGeneratedId = -1;
protected MyBusinessBase()
{
_forceInit = 0;
this.id = Interlocked.Decrement(ref lastGeneratedId);
}

"this.id" is a property that performs a "LoadProperty" on IdProperty.

Because I was initializing this in the constructor, none of the properties in inherited classes were being registered!

Here is a simple test to demonstrate the problem more succinctly:

class RegisterPropertyTest : BusinessBase
{
public void Test()
{
var stringProp = RegisterProperty(new PropertyInfo("Test"));
SetProperty(stringProp, "test");
var intProp = RegisterProperty(new PropertyInfo("Id"));
SetProperty(intProp, 1);
}
}

This code demonstrates the failure: new RegisterPropertyTest().Test();

I suspect that this also affects cases where property values are set in OnDeserialized.

JoshL replied on Thursday, December 18, 2008

Looking into the CSLA code a bit, it appears that this problem is due to the way that FieldDataManager optimizes the list of PropertyInfo objects. On constructor of a FieldDataManager for a given type, all of the PropertyInfo objects registered in the inheritance hierarchy are pulled into a local list. I don't believe that this list is being invalidated when a new property is registered, effectively causing any new properties to be ignored.

One .Net feature is that static field initializers are called as the fields are referenced (you can work around this by setting a static field, as in the _forceInit hack documented in this post). I suspect that this whole problem could be avoided by modifying CSLA to update the FieldDataManager consolidated list when a new property is registered. That way, every time a new Property is referenced by executing code, it would be registered and added to the FieldDataManager; there would be no need to force all of the properties to register at class instantiation.

Rocky, would this be a viable approach?

RockfordLhotka replied on Saturday, December 20, 2008

This isn't a bug, it is a feature :)

Seriously though, I'm (we're) dealing with the way the .NET runtime itself
works here. I'm not making the rules, Microsoft made the rules in 1999, and
we're stuck with them - at least in terms of static field initialization.

I could perhaps do some clever fix-up code to reassess the list of
properties on each SetProperty/LoadProperty call - but the perf implications
are horrendous. How do I know when all the static fields have initialized? I
can't know. So all I can do is one of two things:

1. Assume they've all be initialized before the first
SetProperty/LoadProperty call (which is what I do)

2. Recheck for new field initializations on each SetProperty/LoadProperty
call (which would be slow and complex)

You might wonder why CSLA cares. It is because the order of the fields
matters for serialization. Each PropertyInfo is assigned a numeric index,
and the field values are stored in a list, indexed off that numeric value. I
need a way to generate those index values that is consistent on the client,
the server, on Silverlight, etc. So they are sorted by class (in the
inheritance hierarchy), then by name, then the indexes are assigned.

You then might wonder why the numeric index scheme? I could just allow
positioning to occur based on the order the PropertyInfo objects were
registered. This isn't safe, because there's no specification controlling
the order that methods/properties/fields are placed in the IL by a compiler.
In fact, it is known that VB and C# do not use the same algorithm - and I
shudder to think whether .NET and Silverlight use the same algorithm even
within one programming language.

So I had to come up with some scheme that was repeatable, and independent of
compiler whims.

In the end, then, if someone can come up with some scheme by which all the
PropertyInfo objects in an object instance (across the inheritance
hierarchy) can be ordered in a repeatable manner WHEN THE ORDER OF STATIC
FIELD INITIALIZATION MAY BE UNKNOWN I'm happen to entertain alternatives.

But without that solution, what can (and does) happen is that one class in
the inheritance hierarchy gets initialized, and you can start calling
SetProperty/GetProperty on the fields IN THAT CLASS - and I need to store
those values somewhere such that I can get them back out again, even if the
object is serialized/deserialized.

If some base class LATER gets initialized, then what?

I should also point out that my first run at this was to use a
Dictionary where the full type/field name was used as a key.
This solves the whole problem, but performance was unacceptable. A
dictionary is simply too slow, which is the reason I switched to the numeric
index into a list (array) which is, of course, very fast.

Rocky

-----Original Message-----
From: JoshL [mailto:cslanet@lhotka.net]
Sent: Friday, December 19, 2008 11:51 PM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] Inherited property is not registered?

For some time I have attempted to use the above solution to work around the
"property not registered" error, to no avail. Despite that fact that I had
the above code (with the addition of a call to base.OnDeserialized) in each
of the classes in my inheritance hierarchy, I would still get the error.

Finally I found the problem, which I think might be a CSLA bug: if
SetProperty or LoadProperty is called, no subsequent RegisterProperty calls
are honoured! I had the following in a MyBusinessBase class, inherited from
CSLA:

private static int _forceInit;
private static int lastGeneratedId = -1;
protected MyBusinessBase()
{
_forceInit = 0;
this.id = Interlocked.Decrement(ref lastGeneratedId);
}

"this.id" is a property that performs a "LoadProperty" on IdProperty.

Because I was initializing this in the constructor, none of the properties
in inherited classes were being registered!

Here is a simple test to demonstrate the problem more succinctly:

class RegisterPropertyTest : BusinessBase
{
public void Test()
{
var stringProp = RegisterProperty(new PropertyInfo("Test"));
SetProperty(stringProp, "test");
var intProp = RegisterProperty(new PropertyInfo("Id"));
SetProperty(intProp, 1);
}
}

This code demonstrates the failure: new RegisterPropertyTest().Test();

I suspect that this also affects cases where property values are set in
OnDeserialized.

JoshL replied on Saturday, December 20, 2008

Got it - I figured there was a performance implication, but wasn't aware of the serialization complexities.

It would be nice if the properties could be assigned unique numbers at compile time that you could use, rather than generating indexes based on a sorted list.

RockfordLhotka replied on Saturday, December 20, 2008

Forcing the developer to assign unique numeric index values that span an
inheritance hierarchy seems like a real maintenance nightmare though doesn't
it?

The index values aren't just unique within each class - they are unique for
the object instance, and so must take into account all base classes too.

I totally agree with you though - if there's some way this could be done at
compile time that'd be better.

There is one possible solution using reflection - though it won't work with
Silverlight. I do know the first time a PropertyInfo is requested for a
specific business object type. When that happens, I could loop through the
entire inheritance hierarchy and use reflection to read one static field
value from each class. That would have the same basic effect as the
_forceInit scheme, but would be automatic.

This would work in .NET because reflection can access the non-public static
fields. It won't work in Silverlight because private reflection isn't
allowed. So I am nervous about making such a change, because this discussion
wouldn't go away - it would just get worse (in a sense) because people would
have "working code" that would all of a sudden break when they tried to use
it on Silverlight...

So I would really like to come up with some more elegant answer...

Rocky

daniel_higgins replied on Monday, December 15, 2008

Is this due to a C# optimization, an issue with generics, or a csla quirk? After banging my head against a wall for four hours, I'm a little curious.

RockfordLhotka replied on Monday, December 15, 2008

What? The need to call the base implementation? That's standard OO programming - and is one of the weaknesses of OOP, and specifically with inheritance.

In fact, this is one of the primary reasons the saying is "favor composition over inheritance". Inheritance is one of the most tightly coupled (and thus bad) types of relationship that can exist between classes.

One side-effect of this, is that some methods can be virtual, so a subclass can override that method. The fewer virtual methods the better. Zero would be a good number.

Obviously that's unrealistic...

Why are virtual methods bad? Because the base class(es) might have behavior in those methods. If you override a virtual method, how do you know whether you need to call the base method? And if you do need to call it, do you need to call it first, last, or in the middle of your override?

The only way to know is to look at the code for all base classes, understand that code, and then you can know if you need to make that call.

In short, virtual methods are bad.

Of course all OO code uses inheritance and virtual methods - we take the bad with the good...

In the case of OnDeserialized(), you need to invoke the base method. And it doesn't (shouldn't) matter if you call the base first, last or in the middle.

daniel_higgins replied on Monday, December 15, 2008

My question was about _forceInit. I thought we could rely on C# static field initialization?

RockfordLhotka replied on Monday, December 15, 2008

Me too :)

 

But several months ago I discovered that what I thought were the rules about static fields were not really true. I blogged about it then, and there was a thread on the forum. The real key is a blog post by Brad Abrams on the topic.

 

It turns out that the real rule for static field initialization is this:

 

Static fields in a class are initialized immediately before the first static field in that class is accessed (get or set), or when the static constructor is executed.

 

However, at least during the beta of Silverlight, I noticed a scenario where the static constructor didn’t trigger initialization of the static fields, so I switched completely to using the _forceInit technique.

 

It is important to notice the use of the word “class”, not “object” in that rule. Fields are initialized at the class level, which means that each class in an inheritance hierarchy must have at least one static field touched (get/set) to ensure the fields initialize.

 

On deserialization your constructor code doesn’t get executed. .NET uses a different scheme to create the object instances in that case. This is why you need to ensure OnDeserialized() calls the base implementation, so the _forceInit field in each class gets set.

 

So this is not a C# thing, it is a .NET thing – an implementation decision in the .NET runtime itself.

 

Rocky

 

daniel_higgins replied on Tuesday, December 16, 2008

Thanks for the explanation. I remember hearing "a good programmer looks left and right before crossing a one way street." I guess we need to be looking up and down too.

Kevin Fairclough replied on Tuesday, December 16, 2008

For the record, and I appreciate that there may not be a solution, but this code is giving off an awful smell!

Copyright (c) Marimer LLC