C# design pattern : Generic method?
and thanks for any assistance
For:
public abstract class EntityBase
{
protected voi开发者_运维百科d 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
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.
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.
I would recommend that the base class should never know anything about the derrived classes. In this case: if you add another derrived class you also need to change the base class everytime. Because of this the suggestion of Yann Schwartz is better than your approach.
A problem might be the tight bonds of Customer/Car/... logic with the autdit functionality (see single responsiblity principle). This might be a plus for reflection (as already suggested above and even if it might be slower) but this can get very complex if you want to implement a common aproach for all purposes. It is a better practice to delegate the problem to a separate part you can use like a plugin that can be attached aspect oriented programming. Several frameworks already support this aproach.
If you want to "outsource" your switch case problem you can use the strategy pattern. You can find an example I often used in c# without a special framework here.
精彩评论