XPO Simplified property syntax - a summary

XPO Team Blog
01 February 2007

It’s been a while since we introduced a feature called “simplified property syntax” to XPO. At the time I posted some information about it to the newsgroup, but there have been developments, changes and inconsistent statements about the whole topic, so I thought it would be good to summarize the information in one place.

So what is that simplified syntax we’re talking about? That’s rather easy: we have introduced a number of helper methods in our XPBaseObject class, which allow you to use a shorter form for property implementations. We have previously recommended a certain form for property implementations in persistent classes – see this article, the section titled “Automatic collection of changes” – and this new simplified form takes care of the notification requirement described in that article while providing a concise syntax at the same time.

There are several use cases of the helper functionality we provide, and I want to describe each of them on its own.

Case 1 – automatic value storage, simple syntax – not recommended

public class Person : XPObject {
  ...

  public DateTime Birthday {
    get { return GetPropertyValue<DateTime>(); }
    set { SetPropertyValue(value); }
  }

  ...
}

Now, I’m sure this is very close to the shortest form anybody can imagine for a property implementation. Originally we were planning to recommend this form, with a caveat: there’s a certain performance overhead involved in the algorithm that determines the name of the property behind the scenes – as you can see, that name is not passed into the GetPropertyValue and SetPropertyValue methods, so to do anything useful, XPO has to figure it out itself. Our thought was that in many cases this overhead would be offset by the productivity gain of the simple syntax.

Now we recently found a technical problem that makes this approach more problematic. The issue is in our algorithm that analyzes the call stack to find the name of the property being used – there are cases where this just doesn’t work, apparently because the .NET 2 compiler employs improved mechanisms of inlining method calls.

In case you have already implemented this approach, I’m sorry to say that we will probably not be able to fix the problem itself. We do have instructions for a workaround, so that you can be sure your implementation will not start to malfunction. There are two things you can do, alternatively:

  1. In any assembly that has persistent classes that use the syntax above (or any other related syntax where the property name is not passed in explicitely), add the following assembly level attribute: [assembly: System.Diagnostics.Debuggable(true, true)]
  2. Add the following attribute to each property getter and setter that calls one of our methods with this syntax: [MethodImpl(MethodImplOptions.NoInlining)]

In any case let me repeat, the technical issues combined with the performance problems earn this approach the label Not Recommended.

Case 2 – automatic value storage, recommended syntax

public class Person : XPObject {
  ...

  public DateTime Birthday {
    get { return GetPropertyValue<DateTime>("Birthday"); }
    set { SetPropertyValue("Birthday", value); }
  }

  ...
}

This approach is similar to case 1 above in that it uses automatic storage of the property value (the same functionality that is otherwise exposed via the GetMemberValue and SetMemberValue methods), but the name of the property is being passed in explicitely. Thereby it avoids the performance problem as well as the technical issue of case 1. This approach can be recommended, it has only one drawback: there’s no local variable for the value storage, so if you have business logic implemented in the class and you want to access the value of the field, you always have to go through our helper methods. This may of course, in turn, introduce a performance issue.

Note: While writing this article, I discovered that one of the overload of the GetPropertyValue method that is used in the sample above, does not actually exist – or rather, it has been removed accidentally. This is true for versions up to 6.3.3 – I haven’t looked in which version this overload disappeared. We are going to add the overload back in of course, until then you’ll have to use this of this format instead: return (DateTime) GetPropertyValue(“Birthday”);  In other words, the non-generic version of the method is available, the generic one isn’t.

Case 3 – local variable storage

public class Person : XPObject {
  ...

  private DateTime birthday;
  public DateTime Birthday {
    get { return birthday; }
    set { SetPropertyValue("Birthday", ref birthday, value); }
  }

  ...
}

This is now simple to explain: a local variable is being used to store the field value, and yet another overload of SetPropertyValue is called (once more including the name of the property in the parameter list) to set it. This approach doesn’t have any drawbacks, so it is recommended.

Summary

In all the cases where SetPropertyValue is being used, the syntax is relatively concise compared with the samples we published earlier in relation to the notification requirement for property setters (again, see here for the explanation of that requirement). The SetPropertyValue method, regardless of the overload you use, performs the notification for you. A variant of the approach (case 2) can use automated storage for those cases where you don’t need quick access to a local variable. We recommend you use case 2 or case 3 depending on your needs.

Once again, we don’t recommend you use the syntax described for case 1 above – it may work for you in certain circumstances or when taking good care and applying the necessary workarounds, but the performance of the approach is a problem in any case.

Tags
21 comment(s)
Anonymous
Geoff Davis
Oliver,

Thanks for the article. This now clears up a lot of confusion but I was wondering whether or not you could update your XPO CodeRush templates to reflect the correct behavior to be used. i.e. pps, ppi, etc... Is that a good idea?

Geoff.
1 February, 2007
Oliver Sturm (DevExpress)
Oliver Sturm (DevExpress)
Hi Geoff,
Yes, that sounds like a good idea to me :-) I'll have to find a bit of time, then I'll update them. Thanks for the hint!
1 February, 2007
Anonymous
Robert Fuchs
Good article!

BTW, what about the Megademo???
1 February, 2007
Anonymous
Marc Greiner
Hi Oliver ;

You may know about it already but here is an article on how to speed up reflexion by doing it once only:
http://www.codeproject.com/useritems/Dynamic_Code_Generation.asp

Would this technic help XPO ?
2 February, 2007
Oliver Sturm (DevExpress)
Oliver Sturm (DevExpress)
Hi Marc

Thanks for the hint, but XPO has been doing this, like, forever. We actually have a flag that allows you to switch off this advanced mechanism because there are certain situations where it can create problems. See here for more information: http://www.devexpress.com/Help/Content.aspx?help=XPO&document=DevExpressXpoXpoDefaultUseFastAccessorstopic.htm
2 February, 2007
Anonymous
Robert Fuchs
I just read a bit in your XAF Online Docs, where the property syntax is like this:

public class Person : XPObject
{
  ...
 private DateTime birthday;
 public DateTime Birthday
 {
   get { return birthday; }
   set { birthday = value; }
 }
  ...
}

Are your proposals for properties not applicable/needed/recommended in XAF?
I'm a bit confused now ;-)
2 February, 2007
Oliver Sturm (DevExpress)
Oliver Sturm (DevExpress)
Hi Robert

No, that would be a bug in the XAF docs. With regard to property implementation, the guidelines we're giving for XPO all apply to XAF. Actually, XAF uses UnitOfWork internally, so it's a very good idea to implement your properties "correctly" to be sure everything works.

Thanks for bringing this to our attention.
2 February, 2007
Anonymous
Jascha
Hi Oliver,

I've been using this form:

   public string FirstName
   {
     get { return _firstName; }
     set
     {
       if (_firstName != value)
       {
         string oldValue = _firstName;
         _firstName = value;
         if (!IsLoading)
           OnChanged("FirstName", oldValue, value);
       }
     }
   }

Is this one of the many correct ways of doing it (I like the flexibility of being able to add code to the setter if the property has changed)? I have a snippet set up to create a new property so the typing is not a problem.

BTW, what would CodeRush do for me?

And, you mention the mythical XAF docs - any chance of the promised update to them...
7 February, 2007
Anonymous
David
How would this new syntax work with a Delayed property? There's that ref argument in there.
8 February, 2007
Anonymous
Carel Lotz
Oliver

Will it be possible to change the SetPropertyValue to return a flag indicating whether the value was actually changed.  This way I can easily check in my property setter if I have code that only needs to run if the value was actually changed, i.e.:

property Name {
  get { return name; }
  set  {
     if (SetPropertyValue("Name, ref name, value))
     {
         ....

Thanks
Carel
15 February, 2007
Oliver Sturm (DevExpress)
Oliver Sturm (DevExpress)
Hi Jascha,

"I've been using this form..." - yes, that's fine. It's the "old" suggested form, that some people found somewhat verbose. You could go for "Case 3" in the article above and just add your own code into the setter as needed, that would shorten things somewhat for many cases.

"BTW, what would CodeRush do for me?" - Hehe... many things, see here: http://www.devexpress.com/products/net/idetools/CodeRush/Training.xml - with regard to this topic, it would enable you to use CodeRush's much more fantastic templates instead of VS's boring snippets. That said, I haven't updated my set of XPO templates (published somewhere on this blog) yet - will hopefully get around to doing that soon.

"Mythical XAF docs" - as far as I'm aware, we're still updating the web content of the XAF docs constantly - I haven't checked that statement in a while, maybe I should. We are definitely working on the docs as previously announced and for beta 2 there should be a much bigger set included - I've made that a requirement this time.
All that said - I wonder what we could possibly put into the docs that you wouldn't have figured out yourself by now, or with our help in the newsgroup... :-)
21 February, 2007
Oliver Sturm (DevExpress)
Oliver Sturm (DevExpress)
Hi David,

I saw that you have taken this topic up with support already, and received a negative reply... I can't say anything more than that for the time being. I guess Delayed is not something that most people use for most of their properties, so I think it's an exception, albeit an important one. Thanks for pointing this out.
21 February, 2007
Oliver Sturm (DevExpress)
Oliver Sturm (DevExpress)
Hi Carel,

Yes, that's a good suggestion. I have created a suggestion in Support Center, so you can track the progress here: https://www.devexpress.com/issue=CS28687
21 February, 2007
Anonymous
XPO
Before you panic: this change is unlikely to actually break anything for the large majority of XPO users....
8 March, 2007
Joern G.
Joern G.

In one of my latest applications I coded the property setters the "correct way". Than I noticed that my application became very, very slow. I tracked the problem down and realized that the "correct way" makes XPO load all associated child object's collections, possibly loading 100.000 objects with a single assignment on the 1-side of a 1:n association.

See issue: AS9350 ("XPO should not automatically pre-load an associated collection when I only need to insert a new object into it")

And issue: B90366 ("SetPropertyValue loads associated collection")

The suggested workaround isn't really a good solution and it is not XAF compatible.

With this loss of performance is this still the recommended way?

14 December, 2007
Anonymous
XPO

In future releases of XPO, we will deprecate certain overloads of the SetPropertyValue and GetPropertyValues

14 December, 2007
Joern G.
Joern G.

Oliver, maybe I was not quite clear with my comment.

The performance decrease has nothing to do with the simplified SetPropertyValue method. I am using:

SetPropertyValue("Property", ref _propertyVar, value);

This is still the recommended way, right?

The performance decrease happens as a side effect of calling SetPropertyValue. Within the call to SetPropertyValue XPO loads all related objects of the n-side of an associated relation.

I.e. a simple statement like

myProduct.Category = myCategory;

myProduct.Save();

has the side effect of loading ALL products with the same Category into memory.

14 December, 2007
Oliver Sturm (DevExpress)
Oliver Sturm (DevExpress)

Hi Joern,

I'm wondering - did you see the trackback to the new post that is somewhat related to this and thought it was a reaction to your comment? If so - it wasn't intended to be.

Now, regarding your comment: yes, this is still the recommended implementation. We are aware of the situation with the SC issues you mentioned. The SetPropertyValue call is not really the culprit here, it simply triggers some important functionality that can't currently work without the side effects you mention.

Do you need to use SetPropertyValue? Strictly speaking, no. You can set your own property values, and you can do your own change notification. If you do this (change notification) thoroughly, you might well end up having the same result that we have. We will work on a real solution to this problem, but this requires certain architectural changes, and it will not come along overnight.

All this said, there are workarounds explained in the SC issues. You say these don't work with XAF - I'm not entirely clear why you think that. Can you clarify?

14 December, 2007
Stefan Ericsson
Stefan Ericsson

Hi,

I was looking for some information if SetPropertyValue also takes care of the one-to-one relationship problem that is described in the documentation.

Example:

       set {

           if(owner == value)

               return;

           // Store a reference to the former owner.

           Person prevOwner = owner;

           owner = value;

           // Remove an owner's reference to this building, if exists.

           if(prevOwner != null && prevOwner.House == this)

               prevOwner.House = null;

           // Specify that the building is a new owner's house.

           if(owner != null)

               owner.House = this;

       }

Is this double directed link updated by SetPropertyValue? or do I have to code it like the example?

10 January, 2008
Oliver Sturm (DevExpress)
Oliver Sturm (DevExpress)

Hi Stefan

You have to code it like in the sample code, SetPropertyValue doesn't do that for you.

I would like to mention that I'm usually suspicious when I hear about one-to-one relationships, as there are precious few use cases for them - actually I'm not aware of any that I would consider undisputable. Just a note on the side.

10 January, 2008
Anonymous
XPO

Before you panic: this change is unlikely to actually break anything for the large majority of XPO users

28 March, 2008

Please login or register to post comments.