A different approach to managed backing fields and INotifyPropertyChanged

A different approach to managed backing fields and INotifyPropertyChanged

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


Justin posted on Tuesday, January 27, 2009

So after getting familiar with CSLA 3.6 and Silverlight development I feel like property declarations are somewhat wordy and perhaps redundant and wanted to get a feel for why it was approached this way and what might be the downside to using a more reflective approach.

Take this declaration for a string property from the Rolodex sample:

 private static PropertyInfo<string> CompanyNameProperty = RegisterProperty<string>(new PropertyInfo<string>("CompanyName", "Company Name", string.Empty));
    public string CompanyName
    {
      get
      {
        return GetProperty(CompanyNameProperty);
      }
      set
      {
        SetProperty(CompanyNameProperty, value);
      }
    }

}

So the property type is basically declared four times and the property name twice along with a derivative name three times just to setup a string property.

What strikes me off the bat is the PropertyInfo declaration is basically acting like an attribute declaration, setting up friendly name and default value and then it is used in place of a string literal to connect the proper backing field.

What if a little reflection was used such that it would be declared something like:

    [Attributes.TextField(FriendlyName="Company Name", DefaultValue=String.Empty)]
    public string CompanyName
    {
      get
      {
        return GetProperty(MethodBase.GetCurrentMethod());
      }
      set
      {
        SetProperty(MethodBase.GetCurrentMethod(), value);
      }
    }

This marks up the Property with a TextField attribute that comes from our library we built for previous versions of CSLA, this attribute also as properties for MaxLength and Required etc, that can be honored by a standard rule engine called in SetProperty and the UI.

I know in previous CSLA's PropertyHasChanged() used the stack trace to reflect back and get the propertyinfo without having to use a string literal, but this was problematic with inlining and is in fact pretty slow, and that it was thought that Silverlight would not support as much reflection as it did.

From what I can see MethodBase.GetCurrentMethod() is supported and is much faster than the stack trace approach and to derive the PropertyInfo from the MethodBase is pretty trivial and the results could be cached. If it were implemented properly the difference in performance between the current implementation and GetCurrentMethod would be a string lookup in a hashtable vs an array index lookup.

Any thoughts?

Curelom replied on Tuesday, January 27, 2009

I think this would cause problems with localization.

Justin replied on Tuesday, January 27, 2009

How so?

nermin replied on Tuesday, January 27, 2009

My guess is that one of the reasons to switch to these managed properties was to get away from reflection during serialization and run-time costs that might occur because of it. 

 

From: Justin [mailto:cslanet@lhotka.net]
Sent: Tuesday, January 27, 2009 4:22 PM
To: Nermin Dibek
Subject: Re: [CSLA .NET] A different approach to managed backing fields and INotifyPropertyChanged

 

How so?

Justin replied on Tuesday, January 27, 2009

Serializtion would not require reflection any more than it does now, since behind the scenes there would still be a collection of IFileData's to loop through and serialize/deserialize.

Managed backing fields are more expensive than private fields as it is when using getters/setters, the additional overhead of looking up the managed field by name will be more than an array index, but I would imagnine for most business objects it would be negligable, you do it all the time when using datatables with the field name indexer.

If performance where critical on some properties it would be pretty easy to add a private reference to the IFieldData and use it in the getter/setter to eliminate the indirection at the expense of more lines of code in the get/set.

 

Curelom replied on Tuesday, January 27, 2009

With the attribute
[Attributes.TextField(FriendlyName="Company Name", DefaultValue=String.Empty)]

How would you set the Friendly Name in a localized manner?

Justin replied on Tuesday, January 27, 2009

The same way you would if you used Rocky's approach? They both have string literals in the initialzers?

I would imagine instead of FriendlyName="Company Name" you would do FriendlyName=rm.GetString("CompanyName")

Even better you don't pass a friendly name in the attribute at all, it uses the property name to lookup the proper resource friendly name string. 

RockfordLhotka replied on Tuesday, January 27, 2009

If you use the attribute scheme, how do you get a token for use in AddBusinessRules() and AddAuthorizationRules()?

The purpose behind the static field is to act as a token to represent the property throughout the class, so the property name isn't duplicated all over as a string literal. Any alternative solution must solve that problem.

Justin replied on Tuesday, January 27, 2009

I would argue that it would be better to represent most of that as attributes on the property or class themselves.

So instead of all this:

ValidationRules.AddRule(Csla.Validation.CommonRules.StringRequired, new Csla.Validation.RuleArgs(CompanyNameProperty));

ValidationRules.AddRule(Csla.Validation.CommonRules.StringMaxLength, new Csla.Validation.CommonRules.MaxLengthRuleArgs(CompanyNameProperty, 50));

You simply markup CompanyName like:

[Attributes.TextField(FriendlyName="Company Name", MaxLength=50, Required=true)]

Then there is a common AddRules() that is called that iterates over the members using reflection to setup common rules, on top of that now the UI can simply look at the attirbutes for MaxLength or required.

As for AddAuthorization it would be the same, they should be attributes that take parameter arrays, something like:

[Attributes.CanRead("AdminUser", "RegularUser", "ReadOnlyUser")]

Seems cleaner to me, so instead of using a static field as token to connect the addrules to the property, the attributes are implicitly linked to the property.

 

 

RockfordLhotka replied on Tuesday, January 27, 2009

Attributes for the rules in CommonRules isn’t too hard.

 

Defining an attribute that can describe any arbitrary rule, with arbitrary parameters, is trickier.

 

Also, attributes don’t cover the per-instance scenarios, only the per-type scenarios. While per-type is far more common, the per-instance scenarios are real.

 

Yet another argument for the static field approach is that it is extensible. You can subclass PropertyInfo<T> to add extra metadata about the properties. This can be useful for denoting the database/table/column the value is associated with or other information valuable to the app.

 

In the final analysis though, there’s the weight of history.

 

Already I’m supporting several property declaration models. Dropping them would be a breaking change of non-trivial magnitude for people who have hundreds or thousands of classes in their apps.

 

The attribute model is a good idea, but it would have to be additive to the existing models. Which is certainly possible, but would expand my coding/testing/maintenance scope rather a lot. Already, the weight of supporting the 3.0 and 3.5 (field manager) models is telling. So among the many other concerns, I have to consider whether I think this sounds like fun to do at all, and whether it will be fun to maintain for the next decade.

 

But I’ll add it to the wish list, because it is a good idea, and perhaps at some point it will seem more fun than some of the other cool ideas on the list :)

 

Rocky

Justin replied on Tuesday, January 27, 2009

Normally attributes are per type as you said, mainly because when you call GetCustomAttributes is constructs a new instance of the attribute everytime from the hard coded constructor and has no idea which instance it attached to.

We got around this in order to have "dynamic" attributes, that is what if a string property is required after another property has a certain value?

So all we did was extend BusinessBase to have a GetAttribute(PropertyInfo Property) method, this acted as an instance based attribute cache, that called GetCustomAttributes then stored the attribute references for later use, also this allowed it to pass a reference to the BO instance into the attribute if it needed it for its purposes.

So if you called GetAttribute twice on the same instance you would get back the same attribute instance for that property, and if you set .Required=false it would remain that way and take effect on the next ApplyRules.

We also made some pretty complex attributes, such as our CodedValue one. This attribute marked up which code table the possible values come from in our DB, this attribute was the actual class that handled loading and caching the codes in a static field and allowed searching and validating. That way the coded value could be validated with a common rule and the UI would simply grab that attribute from the property in order to populate a pull down .

Thanks for considering it, we will probably extend 3.6 to use our attributes for a our silverlight project since they have served us well in the past. I mainly wanted to see if there where any gotchas specifically in performance in using reflection in the getter and setter, and if that is why you moved away from it.

 

RockfordLhotka replied on Tuesday, January 27, 2009

One of the most expensive reflection activities is retrieving a custom attribute. I heard it was the most expensive, but haven’t confirmed that.

 

Certainly using reflection is expensive in general, which is why 3.6 eliminates most of it. The combination of the field manager indirection and reflection tanked performance in the initial testing. Getting rid of reflection makes the field manager workable, and the field manager is critical for Silverlight (and Azure) support.

 

So yes, I’d say using reflection in the get/set blocks is off limits going forward, for me anyway.

 

A friend of mine, and co-developer of CSLA .NET for Silverlight, is helping me work through some interesting ideas around the use of lambdas to make RegisterProperty() no longer need the one remaining string literal. The same technique, if we can work it out, should probably eliminate the use of any reflection in CommonRules too, and leads into some features that will likely be necessary to support ADO.NET EF in the future.

 

Remember, I’m just one guy, and while I’d love to do nothing but develop CSLA, I have to do things that actually make money too. So I have to pick my features with some care, to make sure they are interesting (because none of us want me to lose interest), and to make sure I’m ready for .NET 4.0 and 5.0.

 

If CSLA was commercial I’d have a paid dev team and a paid support team, and I could do a lot of other things – like make an attribute-based model by delegating the work to one of my staff. But it isn’t commercial, and rather than building a new feature, I’m creating a series of videos about using CSLA .NET for Silverlight so I can sell them to fund the development I have time to do.

 

Sorry for the rant – I appreciate your passion in pushing a good idea, I really do. But the harsh reality is that I have to balance the existing user base, future .NET directions (including things like Azure) and my ability to create and maintain anything I do – while still having a little time to do something that actually makes money…

 

If I could start with a clean slate and build a new CSLA that’d be cool, there are many things I’d do different now. But that’s similar to Microsoft dropping COM for .NET, or perhaps dropping .NET for whatever comes next – it is a wonderful and terrible thing to contemplate, but it can’t happen more than once every 10-15 years.

 

That said, Oslo might be the answer. Who cares about any of this silly C#/VB syntax crap. One of the things I really want to do (in my spare time – ha!) is to create MCsla – a DSL for CSLA objects. Assuming Oslo and DSLs take off no one need program in C# ever again!! (he says with tongue firmly in cheek)

 

(but I really do plan to do a DSL for CSLA – time permitting)

 

Rocky

 

Justin replied on Wednesday, January 28, 2009

I don't have any hard numbers but I believe the instance based attribute caching approach we used sped up attribute access greatly as a side effect, since again it was just pulling an already live attribute instance out of a dictionary instead of have the runtime instantiate a new attribute as it does on every GetCustomAttribute call. Also attributes can just be used to setup this stuff on BO construction. MS uses attributes all over the place for telling its serializers what to do , so they aren't inherently slow if used wisely.

I hope you don't think I am expecting you to change CSLA, I really appreciate all the hard work put into CSLA, and I believe you could make it commercial if you desired, it has helped us significantly, and as always I respect your opinions on BO development.

I really just wanted to get your opinion and get some holes shot in the attribute based approach, so I know what we would be up against if we tried to use it again for a Silverlight implementation. You have pointed some areas we would need to be weary of if we tried(performance and custom rules)  and this discussion has helped me get up to speed on the new stuff, which again I appreciate.

On the DSL issue, we have gone down that road before, mainly just trying to create some customizability in our app using XML as a simple DSL. Oslo looks interesting, but I think as you have touched on before, DSL usually ends up needing most of the features of a full language over time anyway, why not use one that is already known by existing developers? With .Net having a built in complier and Code Dom in the runtime it's completely possible to say have a user take an existing BO and customize it through inheritance and overriding using C# or VB just like you do when you write an ASP.net page. If you really wanted to have control over the language runtime you could do what a lot of game developers do and use something like LUA for customization, I believe there is a LUA.net implementation.

 

nermin replied on Thursday, January 29, 2009

I would guess that the friend of your you are referring to is either Aaron, or Justin Chase.  Al 3 of us were discussing this idea of using Lambda expressions and adding data binding extensions.  But looking at Aaron’s example (and also few other examples of static reflection)  gave me an idea – independent of your friend- to explore this possibility for  Property Registration )

 

So replacing this code:

private static PropertyInfo<int> IdProperty = RegisterProperty(typeof(Employee), new PropertyInfo<int>("Id"));

with this one:

private static PropertyInfo<int> IdProperty = RegisterProperty<int>(x => x.Id);

 

I needed to add following code – RegisterProperty() override to BusinessBase<T>:

    protected static PropertyInfo<P> RegisterProperty<P>(Expression<Func<T, object>> propertyLambdaExpression)

    {

      PropertyInfo reflectedPropertyInfo = Reflect<T>.GetProperty(propertyLambdaExpression);

     

      return RegisterProperty(new PropertyInfo<P>(reflectedPropertyInfo.Name));

    }

 

Where Reflect<T>.GetProperty()is the code I borrowed from creator of Moq (popular Dynamic Mocking tool) – Daniel Cazzulino.  Here is the implementation of GetProperty() inside Reflect static class:

           public static PropertyInfo GetProperty(Expression<Func<TTarget, object>> property)

           {

                PropertyInfo info = GetMemberInfo(property) as PropertyInfo;

                if (info == null) throw new ArgumentException("Member is not a property");

 

                return info;

           }

 

    private static MemberInfo GetMemberInfo(Expression member)

    {

      if (member == null) throw new ArgumentNullException("member");

 

      LambdaExpression lambda = member as LambdaExpression;

      if (lambda == null) throw new ArgumentException("Not a lambda expression", "member");

 

      MemberExpression memberExpr = null;

 

      // The Func<TTarget, object> we use returns an object, so first statement can be either

      // a cast (if the field/property does not return an object) or the direct member access.

      if (lambda.Body.NodeType == ExpressionType.Convert)

      {

        // The cast is an unary expression, where the operand is the

        // actual member access expression.

        memberExpr = ((UnaryExpression)lambda.Body).Operand as MemberExpression;

      }

      else if (lambda.Body.NodeType == ExpressionType.MemberAccess)

      {

        memberExpr = lambda.Body as MemberExpression;

      }

 

      if (memberExpr == null) throw new ArgumentException("Not a member access", "member");

 

      return memberExpr.Member;

    }

 

Here is the full source of Reflect sample which is what I used in this example:

 

http://www.clariusconsulting.net/blogs/kzu/archive/2007/12/30/49063.aspx

 

Hope this helps!

 

Nermin

 

 

 

 

From: Rockford Lhotka [mailto:cslanet@lhotka.net]
Sent: Tuesday, January 27, 2009 11:26 PM
To: Nermin Dibek
Subject: RE: [CSLA .NET] RE: A different approach to managed backing fields and INotifyPropertyChanged

 

One of the most expensive reflection activities is retrieving a custom attribute. I heard it was the most expensive, but haven’t confirmed that.

 

Certainly using reflection is expensive in general, which is why 3.6 eliminates most of it. The combination of the field manager indirection and reflection tanked performance in the initial testing. Getting rid of reflection makes the field manager workable, and the field manager is critical for Silverlight (and Azure) support.

 

So yes, I’d say using reflection in the get/set blocks is off limits going forward, for me anyway.

 

A friend of mine, and co-developer of CSLA .NET for Silverlight, is helping me work through some interesting ideas around the use of lambdas to make RegisterProperty() no longer need the one remaining string literal. The same technique, if we can work it out, should probably eliminate the use of any reflection in CommonRules too, and leads into some features that will likely be necessary to support ADO.NET EF in the future.

 

Remember, I’m just one guy, and while I’d love to do nothing but develop CSLA, I have to do things that actually make money too. So I have to pick my features with some care, to make sure they are interesting (because none of us want me to lose interest), and to make sure I’m ready for .NET 4.0 and 5.0.

 

If CSLA was commercial I’d have a paid dev team and a paid support team, and I could do a lot of other things – like make an attribute-based model by delegating the work to one of my staff. But it isn’t commercial, and rather than building a new feature, I’m creating a series of videos about using CSLA .NET for Silverlight so I can sell them to fund the development I have time to do.

 

Sorry for the rant – I appreciate your passion in pushing a good idea, I really do. But the harsh reality is that I have to balance the existing user base, future .NET directions (including things like Azure) and my ability to create and maintain anything I do – while still having a little time to do something that actually makes money…

 

If I could start with a clean slate and build a new CSLA that’d be cool, there are many things I’d do different now. But that’s similar to Microsoft dropping COM for .NET, or perhaps dropping .NET for whatever comes next – it is a wonderful and terrible thing to contemplate, but it can’t happen more than once every 10-15 years.

 

That said, Oslo might be the answer. Who cares about any of this silly C#/VB syntax crap. One of the things I really want to do (in my spare time – ha!) is to create MCsla – a DSL for CSLA objects. Assuming Oslo and DSLs take off no one need program in C# ever again!! (he says with tongue firmly in cheek)

 

(but I really do plan to do a DSL for CSLA – time permitting)

 

Rocky

 



Justin replied on Tuesday, February 03, 2009

After giving this some more thought I am liking the dependency property pattern less and less, I already disliked it from WPF but I didn't have to pollute my own classes with it at least. 

If you go and look at the reasoning the WPF guys did dependancy properties is because reflection is slow.

Ok so what did MS do to solve the problem, improve reflection performance? No they recreate a psuedo reflection system except it's glued together manually. How do you connect the dependancy property to the "real" property, well name it with a "Property" suffix and then add SetProperty, GetProperty to the real properties get,set. Why define the property once, when you can do it twice right?

Now I know you are looking at making the PropertyInfo's public to make them accessable from the outside, but at this point why not take it a step further and simply make the PropertyInfo be THE property value?

What I am mean is, that when we looked at using attributes for metadata we also explored another approach, simply making a property values be classes that contain the data and metadata.

For instance delcaring CompanyName becomes something:

public readonly PropertyInfo<string> CompanyName = RegisterProperty<string>(new PropertyInfo<string>("CompanyName", "Company Name", string.Empty));

Where the PropertyInfo class now has a .Value property to access the value. So you would bind to MyCompany.CompanyName.Value or MyCompany.CompanyName.FriendlyName etc.

Why go through all the theatrics of making a second property to hold the first properties metadata and connect the two together? UI controls have done this for a long time, you don't add a string property to a form class then add a second property to the form to hold is position and font of that text, you add a TextBox class that has both a Text property and the other metadata. Why not do this for BO's?

 

RockfordLhotka replied on Tuesday, February 03, 2009

I absolutely thought about exposing a ‘property value container’ instead of a normal property.

 

There are three problems with this that I see.

 

1.       It makes code interacting with the object feel “odd”

2.       It prevents the use of numerous data binding scenarios

3.       Common data mapping/serialization technologies would fail

 

Issue 1 is that all code interacting with your object would be like this:

 

_customer.Name.Value = “Rocky”;

 

When people would expect

 

_customer.Name = “Rocky”;

 

I suspect that’d be a big turnoff for a lot of people.

 

Issue 2 is a bigger deal imo. If you look across the data binding in web, windows, etc, you’ll find that not all of the binding technologies allow (or consistently allow) the use of dot notation to dig into a sub-object. Some do, like XAML, but some don’t. And so this scheme would prevent the use of data binding, or at least complicate the heck out of it and prevent the use of designer support in Windows Forms and Web Forms.

 

Issue 3 may or may not be a big deal. But dot notation isn’t typically supported by serializers like XmlSerializer – but that doesn’t work with CSLA objects anyway. However, dot notation may not work with the ASP.NET MVC helper objects that load/unload objects from postback data – for the same reason DataMapper wouldn’t work without being “dot notation” aware. Of course I can fix DataMapper, but I can’t fix the MVC helpers and other Object-to-Object Mapping tools out there.

 

If we lived in a vacuum, I really do think it would be ideal to have all properties be a richer type. But this model makes interacting with many existing .NET technologies much harder, and so I haven’t pursued the approach.

 

Rocky

Justin replied on Tuesday, February 03, 2009

The reasons you gave are pretty much why we ended up using attributes, at the time(before WPF and dependency properties etc.) they seemed like the best of both worlds for most situations, a simple value type properties with rich metadata attached right to them so it worked fine with databinding, it seemed very natural for our team to create new classes and natural to access the metadata.

We still ended up creating a richer type for our coded values that had .Code and .Description properties.

So we ended up having to do custom databinding and custom serialization anyway, and it ended up working out very well, we put the onus on modifiying the supporting framework so our core BO classes could be coded how we felt they should be.

I think we might look at richer value type containers again at least experimentally, honestly I had hoped MS would continue to refine reflection allowing Property delegates, Property Events, and of course better performance by now, but they seem to be abandoning reflection and attributes in favor of things like dependency properties, very strange to me.

 As far as how natural they are to access(.Value), again we do it all the time with UI controls, it just accepted and works quite well, thats not to say I wouldn't prefer straight up property access with fast rich reflection to get to the property metadata. I know I have seen some talk from the .Net group of adding something like "infoof" to similar to typeof but for retrieving the Info object quickly instead.

Justin replied on Tuesday, February 03, 2009

Just as a follow up to the mythical infoof statement, it looks like some have been able to get it's functionality using linq expression trees http://social.microsoft.com/Forums/en-US/netfxbcl/thread/a29eaf3e-5304-4135-870d-4c05b0cb549b:

Edit sorry just read Nermin's post, looks like he already went over this and had a hand in getting soemthing working already :).

 

Yes, infoof would be a great feature.
But, in C# 3.0 expression trees can do the trick.

Code Block

using System;
using System.Reflection;
using System.Linq.Expressions;

class Person
{
    public int Age { get; set; }
}

class Program
{
    static void Main()
    {
        var person = new Person();
        var age = InfoOf(() => person.Age);
        
        Console.WriteLine(age.Name);
    }

    static PropertyInfo InfoOf<T>(Expression<Func<T>> ex)
    {
        return (PropertyInfo)((MemberExpression)ex.Body).Member;
    }
}

RockfordLhotka replied on Tuesday, February 03, 2009

I should also point out that the primary motivator for introducing the field manager and PropetyInfo was to support the MobileFormatter and Silverlight. All the other features and concepts around it came into being during the discussion of this approach 12-18 months ago - a lot of people here on the forum provided good feedback and input into the design.

But the core requirement is to have a way to get/set property values without the use of reflection. Not because of performance, but because private reflection isn't allowed on Silverlight (or Windows Azure, or CF, or ...).

In other words, relying on private reflection (and/or the BinaryFormatter or NDCS) was clearly going to become a liabiltiy based on what I expected would happen - and I was right - it would have become a liability.

If you look at the field manager, its _primary_ purpose is to maintain a list of property values in a deterministically ordered list, so it is possible for the MobileFormatter to get/set values across multiple platforms in a predictable manner.

A close second to that requirement is performance. Which is why field manager uses a more complex data structure than a simple dictionary. It turns out that a dictionary is too slow (we tried) to make this work - and a dictionary isn't necessarily deterministic across platforms either (hash algorithms may be different on 32 bit, 64 bit and SL).

I appreciate that you are looking at this from the perspective of the code in your business class. And that's valuable. But I started with a set of hard requirements in terms of serialization without private reflection, and the need for reasonable performance, and worked back into what you see today.

As I say, many other design considerations came from external feedback. At the top of that list was to avoid the use of string literal property names throughout a business class.

Certainly the use of attributes can minimize the number of places the property name is required. But in the general case it can't eliminate the need. And so no matter how you look at it, there's the requirement to get rid of the string literal in some manner. And (generally speaking) that means having some compiler-checked token that can represent the property in a way that doesn't overly complicate code, or cause performance issues.

Justin replied on Tuesday, January 27, 2009

I also wanted to hit some other points

RockfordLhotka:

Defining an attribute that can describe any arbitrary rule, with arbitrary parameters, is trickier.

 

From my experience not any more so that the AddRules code, Attributes can have delegates as parameters too. Maybe a more complex example?

edit: I am wrong on this, delegates are not allowed on attribute contructors. Looking back we never really needed to do this, attributes handled 95% our rules validation and anything custom to that property was just coded in the setter.

RockfordLhotka:

Yet another argument for the static field approach is that it is extensible. You can subclass PropertyInfo<T> to add extra metadata about the properties. This can be useful for denoting the database/table/column the value is associated with or other information valuable to the app.

  

For me this is exactly what attributes are for, and what we have used them for, putting metadata on a property, and have used them for all those things(table name etc.). Attributes are just classes remember, they are as extensible as you want them to be.

Copyright (c) Marimer LLC