Code generation hooks for property changing/changed

Code generation hooks for property changing/changed

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


skagen00 posted on Monday, July 17, 2006

I apologize if this is a little off-topic, but I know a few here have probably tackled this problem.

I am continuing to go into the process of code generation using partial classes with the codesmith templates for C#.

The trick with the usage of partial classes being the various hooks necessary to extend behavior of generated code - the current issue I'm running across is with the setting of properties - both prior to the value change and immediately afterwards.

One example of the prior to change is with, for instance, social security numbers - I want to allow various formats to be assigned to the social security number, but to have it automatically formatted to the proper format within the setter. Here, I'd want this to occur before _socialSecurityNumber = value.

An example of after the change is with name components. When a user has various name parts (first/last/middle/suffix/prefix), changes to these will affect the "derived names" (including a sort name). The user has the ability to modify this derived name and hence it has its own state in the object. So, after a name part is changed and for instance _lastName = value, I want to DeriveNames().

I considered including as meta-data of the objects (in the xml definition file) a includePropertyChanging and includePropertyChanged boolean flags, and when explicitly set to true I would include the necessary call to a specific and properly typed function for the handcrafted class to implement. Clearly, the class wouldn't compile with these functions not implemented, but I'd be explicitly saying that they will be implemented by utilizing the flags.

With respect to the property changing method, it would return a value of the same type and would cause the "value" in the setter to potentially change - that is - my SocialSecurityNumberPropertyChanging() would end up returning the properly formatted value, and assignment would occur to the formatted value.

I'm sure at a minimum this gets my general problem across... I could also have a single "PropertyChanging()" and "PropertyChanged()" method (not strongly typed and using a switch statement).

Appreciate any advice - thanks!

 

RockfordLhotka replied on Monday, July 17, 2006

You could also use private events for this purpose. In VB this is an excellent option, because you can use WithEvents/Handles to automantically hook the events - meaning in the user code the only code required are the event handlers. In C# this isn't as nice, but is still workable, and is why I added the Initialize() method to all the base classes (so you can insert the event hookup code).

Another option is to end up with THREE classes (two genned, one user):

CustomerBase.xx (genned)
Customer.genned.xx (genned)
Customer.xx (user)

In CustomerBase you would define protected virtual/Overridable methods for all your pre/post get/set scenarios. Then in Customer.genned your property implementations would invoke those methods - which would always work, but would do nothing. Then the developer could override them in Customer on an as-needed basis.

I like this option because it avoids the overhead of events, and allows the user code to only implement methods they care about with no extra work - even in C# - so the user code is very focused. It is also strongly typed.

The only drawback is that you need to code-gen the base class as well as the partial class, so it is like a combination of the standard inheritance technique with the new partial class technique.

But if you think about why partial classes work so well for Windows Forms and Web Forms, it is not in small part because Microsoft's base classes (Form and Page) provide useful hooks. On the other hand, it is also the case that partial classes were designed for event-driven scenarios, with the basic assumption being that the user code could just handle a set of events to do its work...

xal replied on Monday, July 17, 2006

I'm not sure If I get what you're trying to say, but BusinessBase has a method you can override:


    Protected Overrides Sub OnPropertyChanged(ByVal propertyName As String)
        MyBase.OnPropertyChanged(propertyName)
        If propertyName = "Name" Then
            ...
        End If
    End Sub

Of course, in order for this to work you have to code your props somewhat like this:

Public Property Name As String
    Get
        CanReadProperty("Name", True)
        Return m_Name
    End Get
    Set (ByVal value As String)
        CanWriteProperty("Name", True)
        If m_Name <> value Then
            m_Name = value
            PropertyHasChanged("Name")
        End If
    End Set
End Property



Andrés

skagen00 replied on Monday, July 17, 2006

I think the route Andres is suggesting is a nice simple approach that gets me through everything I need to worry about at this point. Your post, Rocky, is useful in thinking about future hooks that may need to be added to accomodate more flexibility.

Good replies both, thank you.

Chris

 

rasupit replied on Monday, July 17, 2006

Chris,

When creating the partial class, I was debating whether I need to add hooks before and after value assignment in property set.

I figured that hook after value assignment is not needed since you can either override the OnPropertyChanged (just like Andres has shown) or override PropertyHasChanged if you need to inject the code before validation take place.

I ended up not implementing hook before value assignment.  The only time I see this is needed when you need to add code that need to use the original value.  In my experience this is rarely happening, and by not adding this hook I could make the code less complex and possibly (yet to test) avoid performance issue.

Of course, somebody might experience this differently.  If you do, I would like to hear your experience.

Ricky

skagen00 replied on Tuesday, July 18, 2006

Ricky,

As I took Andres suggestion to override OnPropertyChanged and I went through and implemented my handcrafted pieces, I found no requirements that necessitated an extra hook before the property changed (like you say, the only reason is to need to know what the original value is).

That's not to say that perhaps there won't be a case like that, but since I didn't encounter one I didn't want to pursue it.

Thanks for your input

Chris

 

xal replied on Tuesday, July 18, 2006

I strongly believe that if you have something that escapes the scope of code generation, you shouldn't generate it. So if I find myself needing to do something special before a property changes I will most likely not generate that property and hand code it. You can use hooks in fetch methods to fill it's value anyway.

Either way, even if you wanted to generate that you could just have another variable that holds the "previous value", and you can still handle things inside OnPropertyChanged and keep that "previous value" field up to date.

I've been working on CslaGen for a long time now, and I believe that sort of stuff is out of the scope of code generation (at least for cslagen's part). I don't think a project of this nature should try to be everything to everyone.

Andrés

Copyright (c) Marimer LLC