Problem with RegisterProperty and Inheritance

Problem with RegisterProperty and Inheritance

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


Craig.Young posted on Wednesday, July 29, 2009

Hello All,

I have the following object inheritance model.

[Serializable]
public abstract class CustomBase : BusinessBase<CustomBase> { ... }

[Serializable]
public class Class1 : CustomBase { ... }

[Serializable]
public class Class2 : Class1
{
        private static PropertyInfo<string> _cityProperty =
            RegisterProperty(typeof(string), new PropertyInfo<string>("City", "City"));
        public string City
        {
            get { return GetProperty(_cityProperty); }
            set { SetProperty(_cityProperty, value); }
        }
}

I have run into some issues with RegisterProperty not initializing correctly _cityProperty. I know this because when I set and/or get Class2.City and checkout the _cityProperty the internal index inside the FieldManager is -1 and an exception is thrown when SetProperty is call similar to:

System.InvalidOperationException: One or more properties are not registered for this type ---> System.IndexOutOfRangeException: Index was outside the bounds of the array.\r\n   at Csla.Core.FieldManager.FieldDataManager.FieldExists(IPropertyInfo propertyInfo) in C:\\Code\\Sandbox\\CSLA.NET\\3.7.0-90710\\Source\\cslacs\\Csla\\Core\\FieldManager\\FieldDataManager.cs:line 313
--- End of inner exception stack trace ---
   at Csla.Core.FieldManager.FieldDataManager.FieldExists(IPropertyInfo propertyInfo) in C:\\Code\\Sandbox\\CSLA.NET\\3.7.0-90710\\Source\\cslacs\\Csla\\Core\\FieldManager\\FieldDataManager.cs:line 317

Also I've tried to register the Property using a lambda expression and I've noticed that the only available Properties where the ones defined in CustomBase.

So, am I doing something odd or wrong - or has anyone come across this before and has a possible work around. I have read pages 248-250 in the book and have tried the recommendations however; they do not work.

Any help would be really awesome! Thanks.
-Craig

RockfordLhotka replied on Wednesday, July 29, 2009

You are using RegisterProperty() incorrectly.

RegisterProperty(typeof(string), ...)

is saying that your property is owned or contained in the 'string' type, which is is not. It is contained in your business class type.

You are far better off (exception in criteria and command objects) using the RegisterProperty() overload that doesn't require that explicit type parameter, and probably the one that uses a lamba expression to get strong typing:

RegisterProperty<string>(c => c.City);

Also, and this is up to you of course, the convention is to name the field something like CityProperty, not _cityProperty. This convention comes from Microsoft's convention for dependency properties, which are very similar to managed properties in CSLA.

The value will become very apparent if you externalize your data access layer, because in that case you'll probably make these static fields public (so the DAL can use them), and you'll end up with a bunch of oddly named public members on your class.

Craig.Young replied on Wednesday, July 29, 2009

Gosh, after searching around a little bit more on the forum I've found Rocky's post on his current implementation of this and why it does / doesn't work.

http://forums.lhotka.net/forums/post/29278.aspx

Very interesting read. FWIW, I've tried the following pattern as well to try and solve the problem, however again - this seems to not work.

private static PropertyInfo<string> _addressProperty = RegisterProperty<string>(typeof(string), new PropertyInfo<string>("Address"));
        public string Address
        {
            get { return GetProperty(_addressProperty); }
            set
            {
                if (!base.FieldManager.FieldExists(_addressProperty) || ReadProperty(_addressProperty) == null)
                {
                    LoadProperty<string>(_addressProperty, value);
                }
                else
                {
                    SetProperty(_addressProperty, value);
                }
            }
        }

This fails entirely because base.FieldManager.FieldExists(_addressProperty) throws the same exception. When I try to set the static PropertyInfo field at run-time dynamically vs at object creation, the object is always return with an index of -1. Hmm... food for thought.

RockfordLhotka replied on Wednesday, July 29, 2009

Again, you are using the overload of RegisterProperty() that takes a type argument as the first parameter.

That first parameter is the type of the containing object, and you are using typeof(string). So you are saying this property is contained in the string type - which is clearly is not.

I strongly recommend using one the RegisterProperty() overloads that doesn't require that first type parameter, because that parameter just causes copy-paste maintenance errors all the time. Let the compiler do the work for you and use one of the simpler overloads.

Craig.Young replied on Wednesday, July 29, 2009

Hey, you type too fast!

I just figured out what you were trying to tell me in your first reply and eventually got it to work.

private static PropertyInfo<string> _addressProperty = RegisterProperty(typeof(Class2), new PropertyInfo<string>("Address"));

I had to use the non-generic version because it seems the strongly typed generic of RegisterProperty is pointing the base CustomBase object for the Lambda expression.

Our CustomBase class inherits from BusinessBase as: BusinessBase<CustomBase>
:-)

Thanks for your help Rocky!

RockfordLhotka replied on Wednesday, July 29, 2009

Ahh,

 

You might consider changing your custom base class to preserve the intended semantics of the CSLA base classes – otherwise you not only lose out on the RegisterProperty() behaviors, but things like Save() and Clone() will return the base type and you’ll have to do explicit casting.

 

Rocky

Craig.Young replied on Wednesday, July 29, 2009

Yeah I realize that my variables are named that way. It's just my naming convention that determines what is a private field vs a publicly available field. If the PropertyInfo was public I choose your recommended naming convention. But that is very interesting in that I should use RegisterProperty (non-generic) when I am not using lambas. I'll give that a go - as well as the recommendation from your forum post

http://forums.lhotka.net/forums/permalink/29278/26436/ShowThread.aspx#26436
:-)

Copyright (c) Marimer LLC