views:

134

answers:

2

Hello, and thanks for any assistance

For:

public abstract class EntityBase
{    
 protected void Create(EntityBase c)    
 {        
    Log.Audit(c);
 }
}

public class Customer : EntityBase
{    
 public void CreateCustomer(Customer c)    
 {        
  Create(c);    
 }    
 }
}

public class Car : EntityBase
{    
 public void CreateCar(Car c)    
 {        
  Create(c);    
 }    
 }
}

For the above example 1) How would you implement the method signature for: Log.Audit(c);

2) Inside the method Audit(c) we will need to cast c to it's appropriate type, and go through the entire object's properties for auditing purposes. How would this be accomplished. I'm thinking something like....

public Audit(T t)
{
 switch (t.GetType())
 {
 case Customer:
    //Audit Customer
    Audit(<Customer> t); 
    break;
 case Car:
    //Audit Car
    Audit(<Car> t); 
 }
}

Just a guess, any help would be great.

Note: If you can think of a better way of architecting this method, please let me know.

Thanks again. Steven

+2  A: 

I almost always use reflection when doing auditing. If you have properties that have attributes (say ColumnAttribute) that distinguish them you can use the attributes to find those properties that you want to audit. You can always create an attribute to use and apply it if need be. The simplest thing, however, is just to audit the public properties of the class.

public void Audit( T t )
{
     foreach (var property in t.GetType().GetProperties())
     {
         var value = property.GetValue(t,null);
         ...do something with property.Name and value...
     }
}

You can get idea of how I use this for LINQ to SQL at http://farm-fresh-code.blogspot.com/2009/05/auditing-inserts-and-updates-using-linq.html.

tvanfosson
+3  A: 

In a method, when you have switches or if/else constructs to decide how to dispatch methods, it's a telltale sign you're not using polymorphism.

One solution would be to make Audit() a virtual method of EntityBase and have Audit call it on the instances (so you override Audit in Customer or Car)

You can as a bonus provide a default implementation using reflection that goes through every property of the inherited class to dump it.

public abstract class EntityBase
{    
     protected void Create(EntityBase c)    
     {        
       Audit(c);
     }

     public virtual void Audit()
    {
    //Default audit code here, using reflection for instance
    }     
}

public class Car : EntityBase
{
    //Does not override, uses default Audit Code
}

public class Hamster : EntityBase
{
    public override void Audit()
    {
     //Specific code here..
    }
}

If you don't want to have the Audit responsability inside the Entity class or one of its inheritors, you'll have to go the reflection way.

Yann Schwartz