NOTE: This post was originally published on July 4, 2008
I love NHibernate but one of the things that bothers the hell out of me is that i keep forgetting to add the virtual keyword to each method or property in my entities. And since NHibernate needs your classes' properties and methods to be virtual, this causes run-time errors when i run my tests. Since i'm already using custom compile time checks, i figured i might as well add another one... from now on, i want my compilation to fail if any of my NHibernate entities have public methods/properties that aren't marked virtual.
Once again, it's PostSharp to the rescue:
using System;
using System.Reflection;
using PostSharp.Extensibility;
using PostSharp.Laos;
namespace Northwind.Aspects
{
[Serializable]
[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Method | AttributeTargets.Property)]
[MulticastAttributeUsage(MulticastTargets.Method, TargetMemberAttributes = MulticastAttributes.Managed |
MulticastAttributes.NonAbstract | MulticastAttributes.Instance |
MulticastAttributes.Protected | MulticastAttributes.Public)]
public class RequireVirtualMethodsAndProperties : OnMethodBoundaryAspect
{
public override bool CompileTimeValidate(MethodBase method)
{
if (!method.IsVirtual)
{
string methodName = method.DeclaringType.FullName + "." + method.Name;
var message = new Message(SeverityType.Fatal, "MustBeVirtual",
string.Format("{0} must be virtual", methodName), GetType().Name);
MessageSource.MessageSink.Write(message);
return false;
}
return true;
}
}
}
And then we make sure this check is applied to my NHibernate entities:
#if DEBUG
[assembly: RequireVirtualMethodsAndProperties(AttributeTargetTypes = "Northwind.Domain.Entities.*")]
#endif
Now, whenever i forget to mark my properties/methods as virtual, i get this:
EXEC : error MustBeVirtual: Northwind.Domain.Entities.Region.RemoveTerritory must be virtual
EXEC : error MustBeVirtual: Northwind.Domain.Entities.Region.AddTerritory must be virtual
EXEC : error MustBeVirtual: Northwind.Domain.Entities.Region.get_Territories must be virtual
EXEC : error MustBeVirtual: Northwind.Domain.Entities.Region.set_Description must be virtual
EXEC : error MustBeVirtual: Northwind.Domain.Entities.Region.get_Description must be virtual
EXEC : error MustBeVirtual: Northwind.Domain.Entities.Region.set_Id must be virtual
EXEC : error MustBeVirtual: Northwind.Domain.Entities.Region.get_Id must be virtual
...
Done building project "Northwind.csproj" -- FAILED.
And there we go :)