A different approach for saving programmer changes while using Code Generator

Before I’ll talk about a different solution, let’s talk about the default solution so we could compare them.


Demonstrate the (default)missionary approach – Inheritance:


Let’s view a very simple piece of code to make things a bit more tangible:


UsersDal.generated.cs file:


This file is auto-generated based on Users table from our database:


// This file is auto-generated.
// Any changes to this file can be lost in the next code generation.
// If you need to change something – check UsersDal.cs

public abstract class UsersDalBase
{
   public virtual void Add(User u)
   {
      Console.WriteLine(“Doing \”base\” behavior for UsersDalBase.Add(User u)”);
   }
}



You can imagine that in reality, UsersDalBase.Add method will actually open a connection against the database and insert the received user object. As you can tell, this file should be changed only by the code generator (if you change the table structure or relations for example).



Let’s look at our stub class that inherit from the “Base” class.

UsersDal.cs file:


// This file is safe for edit !

public class UsersDal : UsersDalBase
{
}


This file is also generated but only as an empty stub class which can be used if we(the programmers) need to change the default behavior in UsersDalBase. Any upper layer(Business Layer, WS, whatever) in our application will use only UsersDal so any changes to UsersDal or UsersDalBase will be reflected automatically.


Now, let’s say that the generated code isn’t good enough. I want to check some conditions on the user object before actually adding it to our database. All I have to do is simply override the Add method in our UsersDal class.


public class UsersDal : UsersDalBase
{
   public override void Add(User u)
   {
      if (Validator.IsValid(u))
      {
         base.Add(u);
      }
      else
      {
         throw new ArgumentException(“The given object is invalid.”);
      }
   }
}


Now, if I want to re-generate my code due to some changes in my ERD, all I have to do is to replace the UsersDalBase.generated.cs file and my custom changes remains untouched.


The only problem with inheritance is it’s limitation:


(1) You can inherit from one class only and by using inheritance I can’t inherit from GenericDal (unless I’ll add another layer of inheritance, not ideal).

(2) I need to give “high” access modifier(public) to my UsersDalBase. We use UsersDalBase just to allow custom changes. In a perfect world UsersDalBase should be internal (Data Access Layer project).



Let’s look at a different solution – events based separation:


We want to keep our original ability to make changes in our code without losing it on the next code-generation. First, let’s look at a very raw UsersEventArgs I’ll use later on:


public class UserEventArgs : EventArgs
{
   private User m_user;
   private bool m_cancel;

   public UserEventArgs(User u)
   {
      m_user = u;
   }

   public User User
   {
      get { return m_user; }
      set { m_user = value; }
   }   

   public bool Cancel
   {
      get { return m_cancel; }
      set { m_cancel = value; }
   }
}


Notice the “Cancel” property, we’ll use it later on.


UsersDal.generated.cs (version 2)


public partial class UsersDal
{
   protected event EventHandler<UserEventArgs> Adding;
   protected event EventHandler<UserEventArgs> Added;

   public void Add(User u)
   {
      UserEventArgs ea = new UserEventArgs(u);

      RaiseAdding(ea);

      if (!ea.Cancel)
      {
         // default logic
         AddUser(u);

         RaiseAdded(ea);
      }
   }

   protected virtual void AddUser(User u)
   {
      // generated code
      Console.WriteLine(“Doing \”base\” behavior for UsersDal.Add”);
   }

   protected void RaiseAdding(UserEventArgs e)
   {
      EventHandler<UserEventArgs> handler = Adding;
      if (handler != null)
         handler(this, e);
   }

   protected void RaiseAdded(UserEventArgs e)
   {
      EventHandler<UserEventArgs> handler = Added;
      if (handler != null)
         handler(this, e);
   }
}


(1) As you can see, I’m raising an event just before adding the user and another event just after adding the user.
(2) We are using partial class (UsersDal).


UsersDal.cs (version 2):


public partial class UsersDal
{
   public UsersDal()
   {
      // Register to (self) events:
      this.Adding += new EventHandler<UserEventArgs>(UsersDal_OnAdding);
      this.Added += new EventHandler<UserEventArgs>(UsersDal_Added);
   }

   protected void UsersDal_OnAdding(object sender, UserEventArgs e)
   {
      if (!Validator.IsValid(e.User))
      {
         e.Cancel = true;
         // I can also throw a new exception, that will work as well.
      }

      // If e.Cancel remains false (default) the basic (generated)behavior will be executed.
   }

   void UsersDal_Added(object sender, UserEventArgs e)
   {
      // Console.WriteLine(“Doing custom UsersDal.Add – on added”);
   }
}


Calling e.Cancel = true will actually stop the flow in the generated file. You can obviously add more code – according to your needs.


This separation will able you to do just about everything you could via inheritance and then some:


(1) The ability to add another partial class in order to separate class by “topics”.
(2) The ability to add more listeners(event handlers).
(3) The ability to inherit from other classes, if you need to.
(4) No need for extra class in our namespace which means less confusion to the programmer – “Should I use UsersDalBase ? Oh.. wait… I remember something about it… Ya! I need to use UsersDal…”.


Hope it helps.

 

Oren Ellenbogen

 

One thought on “A different approach for saving programmer changes while using Code Generator

  1. Personally I don’t think this is particularly elegant, any time I see an object subscribing to its own events I feel a little ill. In this case these events only exist for the object (and derivations) to listen to which, to me, is more than a little confusing.

    As you point out inheritance always has a cost, using up your single chance to inherit so maybe you do want to move away from that. However whilst you’ve pointed out problems with the inheritance approach I think you’ve been overly forgiving of flaws in the solution.

    Looking at the 4 advantages of your solution here’s the way I’d see it:
    (1) Adding more partial classes is likely to add to the confusion, especially if each of them is hooking in to change (override) the behavior.
    (2) Yup but since its protected its only within that inheritance hierarchy so its a little false.
    (3) If you need to, and this isn’t a published API, then you can always refactor later anyway.
    (4) I presume the programmer here is someone looking to extend your object? If so seeing these events is likely to confuse them more than a bit of inheritance.

    I haven’t tried but couldn’t you go with the partial class approach but instead of raising fake events just have a ValidateCanAdd method thats called by the generated code prior to adding an item, however the generated code won’t have an implementation of that method. Instead you provide the implementation in the other part of the partial class that you implement. This is more consistent with what I’d expect if I was using your classes (especially as its similiar to what Microsoft did with CollectionBase.OnValidate).

Comments are closed.