Design by Contract with AOP

posted @ Wednesday, October 19, 2005 1:00 AM

 

Over a year ago I discussed with Joe Duffy, a program manager on the CLR team about the concept of design by contract. Recently I had a similar disucussion with Richard Hale Shaw and Cyrus Najmabadi a developer on the C# compiler team at Microsoft while I was at the MVP Global Summit. I thought I would put together a quick example of how this could be applied, spawning off of my previous post discussing AOP. This example allows the developer to place certain restrictions on a method and for those restrictions to be applied before the method is actually called. In this example, if those restrictions aren't meet, the method is not called. If you step through the code, you will notice the second call to SayHello does not get called. Since this is simply an example, there is a lot that could change with this. For one, we would want to include the concept of an EpilogAttribute which would allow the developer to place constraints on the return value of the method as well. I'm curious what others think of something like this?

 

using System;
using
System.Reflection;
using
AopAlliance.Intercept;
using
Spring.Aop.Framework;
using
Spring.Aop.Interceptor;
using
Microsoft.VisualStudio.TestTools.UnitTesting;

namespace
DeveloperNotes
{
public class ConstraintInterceptor : IMethodInterceptor
{
public object Invoke(IMethodInvocation invocation)
{
MethodInfo mi
= invocation.Method;
if
(mi != null)
{
Object[] attrs
= mi.GetCustomAttributes(typeof(PrologAttribute), true);
if
(attrs != null && attrs.Length > 0)
{
PrologAttribute pl
= attrs[0] as PrologAttribute;
if
(pl != null)
{
object[] args = invocation.Arguments;
if
(args != null)
{
bool results = !Assert.Equals(args[pl.Index], pl.RVal);
if
(results)
return invocation.Proceed();
else
return null;
}
}
}
else
{
return invocation.Proceed();
}
}
return null;
}
}

public class PrologAttribute : Attribute
{
public int Index;
public object
RVal;

public
PrologAttribute() { }

public PrologAttribute(int index, object rval)
{
this.RVal = rval;
}
}

public class ObjectFactory
{
public static K CreateObject()
{
T obj
= Activator.CreateInstance();
if
(obj != null)
{
ProxyFactory factory
= new ProxyFactory(obj);
factory.AddAdvice(new ConstraintInterceptor());
return
(K)factory.GetProxy();
}
return default(K);
}
}

public interface IPerson
{
void SayHello(string name);
}

public class Person : IPerson
{

[Prolog(
0, "")]
public void SayHello(string name)
{
Console.WriteLine(
"Hello {0}", name);
}
}

class Program
{
static void Main(string[] args)
{
IPerson p
= ObjectFactory.CreateObject();
if
(p != null)
{
p.SayHello(
"Nick");
p.SayHello("Nicholas");
}
Console.Read()
;
}
}
}