posts - 12, comments - 12, trackbacks - 4

My Links

News

Zouak Consulting


Archives

Image Galleries

THE category

Static Method "Inheritance" via Generics

I was working with a customer a couple of months ago where they were repeating code again and again, for every business entity, so that each business entity had the same base set of persistance methods:

  • RetrieveById
  • Save
  • CreateNew

Before you ask, there lots of reasons why it had to be done this way and was done this way, none of which I'm really supposed to talk about, but suffice it to say that we all occasionally run into a situation where we want a bunch of classes to have the same static methods without recoding this every time and then needing to fix bugs in all of them when we find something. There's a way to use generics to get this effect, this “inheritance” however there is no overriding as such.

The example I'm using below is based around the idea of data persistance, one entity is a Desk and another is a Student. Each has its own PersistanceManager class. I'm not saying this is a great approach to take, but it is easy enough to explain with this that you should see how it is relevant to your own scenarios.

// This interface ensures that the class is able to be populated from a provided datarow and includes an Id property.

public interface IRowPopulatable {
    Int32 Id
    {
        get;
        set;
    }
    void PopulateFrom(DataRow row);
}

// This class represents a Student, though it is mostly empty for purposes of this article.

public class Student : IRowPopulatable
{
     protected Int32 _id;

     public Int32 Id
     {
         get { return _id;}
         set { _id = value; }
     }

     // The PopulateFrom method in this class is empty as it doesn't matter relative to the article

     public void PopulateFrom(DataRow row)
     {
         return;
     }// PopulateFrom
}// Student

// This class represents a Desk, though it is mostly empty for purposes of this article, it has some differences from the Student.

public class Desk : IRowPopulatable
{
   protected string _styleName;
   protected Int32 _id;

   public Int32 Id
   {
      get { return _id; }
      set { _id = value; }
   }// Property ID

   public string StyleName
   {
      get { return _styleName; }
      set { _styleName = value; }
   } // Property StyleName

   public virtual void PopulateFrom(DataRow row)
   {
      return;
   }// PopulateFrom

   public Desk() {
      _id = -1;
      _styleName = string.Empty;
   }// Desk Constructor
}// Desk

// This is the main important class, the generic class. It uses a generic T, requires that the type T implement the interface IRowPopulatable simply to  allow the static RetrieveById class to be able to be implemented once, generically. The new() requirement is because of the T result = new T().

public class PersistanceManager where T : IRowPopulatable, new()
    {
        public static T RetrieveById(Int32 id) {
            // Defensive check of the id parameter not provided for simplicity

            DataTable dt = new DataTable();
            // Fake Data Retrieval populating dt with a datatable

  T result = new T();

  result.PopulateFrom(row);

            return result;
        }// RetrieveById

        public static void Save(T entity)
        {
        }// Save
    }// PersistanceManager

   // This class is an example of a PersistanceManager that focuses exclusively on Desk. Note that it has no code other than a default constructor, which is not needed but is provided to illustrate that there is no code missing. The DeskPersistanceManager automatically has a Save and a RetrieveById static method.

    public class DeskPersistanceManager : PersistanceManager
    {
        // The DeskPersistanceManager now has a RetrieveById method that returns
        // a desk with no addition code

        public DeskPersistanceManager()
        {
        }// DeskPersistanceManager
    }// DeskPersistanceManager

   // This class is an example of a PersistanceManager that focuses exclusively on Student. Note that it has no code other than a default constructor, which is not needed but is provided to illustrate that there is no code missing. The StudentPersistanceManager automatically has a Save and a RetrieveById static method. However as you would expect with generics, StudentPersistanceManager and DeskPersistanceManager do not have a common parent from which they inherit.

    public class StudentPersistanceManager : PersistanceManager
    {
        // The StudentPersistanceManager now has a RetrieveById method that returns
        // a student with no addition code

        public StudentPersistanceManager()
        {
        }// StudentPersistanceManager

        public static new void Save(Student sampleStudent)
        {
            // Do my own thing
            return;
        }
    }// StudentPersistanceManager

With all of this code providing the interface, the two entities, the generic 'base' PersistanceManager and the 2 entity-specific PersistanceManagers we can now do the following

class Program
{
   static void Main(string[] args)
   {
      Desk sampleDesk = DeskPersistanceManager.RetrieveById(5);
      Student sampleStudent = StudentPersistanceManager.RetrieveById(3);
   }// Main
}// Program

When you look at the Intelli-Sense for DeskPersistManager and StudentPersistanceManager you see the RetrievebyId which is specific to them, i.e. one returning Desk and the other Student respectively. Both have also a Save method, as expected.

The purpose of this technique is to allow you to have a means for avoiding recoding static methods again and again between classes for shared purposes. It does not allow you to have a defined interface, or anything, that would then allow you to iterate over multiple classes using them polymorphically as some common parent because they don't have a common parent. Remember, in .NET List and List do not have a common parent of List, they are effective ListInt and ListString classes with no ancestors.

As always, let me know what you think. driss @ zouak . com

PS: Extending

Want your own static Save method in StudentPersistanceManager or need to change something? For example:

public static new void Save(Student sampleStudent) {

// Trivial but effective

return ;

}

As you would expect, if you don't add the New or you add any additional Save method, you will get a warning that you are hiding the Save method from the PersistanceManager. However, part of the point is to standardize your approach so use this with caution.

Print | posted on Sunday, July 02, 2006 11:29 PM |

Feedback

No comments posted yet.
Post A Comment
Title:
Name:
Email:
Website:
Comment:
Verification:
 
 

Powered by: