I've been using the LINQ to Entities and LINQ to SQL modeling tools a lot recently. They are pretty good. Having experienced the pain of disconnectedness in using myGeneration and NHibernate in my company's re-architecture effort over the last year, it feels good to have some O/RM support in the Visual Studio IDE and in the C# language. I can say with certainty that if LINQ had been ready in April of 2007, when I had to make the choice, I would never have chosen to use NHibernate.
It's not that NHibernate is bad. Quite the contrary. It's both rich and expressive. But the level of effort that's required to get an effective NHibernate implementation up and running is overwhelming for most companies. True expertise must be developed to use NHibernate effectively. I've experienced that phenomenon first hand. It can take literally weeks or months if you have a complex schema with which you must integrate. And you cannot overlook the fact that while you may be able to afford to train one or two of your developers to the required level of expertise in using NHibernate, the real value of any software system comes from getting most of your staff to participate in the development process. Otherwise, you will create a bottleneck for new development, maintenance and problem triage.
LINQ, on the other hand, can be learned pretty well by intermediate-skilled developers in a few days, in perhaps a week at most, against a comparably complex schema. And with the help of the Query Comprehension Syntax, most developers who are comfortable writing SQL queries usually feel right at home with LINQ in no time at all. Granted, to achieve true expertise with LINQ also takes weeks or months. However, in my experience, to be functional with LINQ, expertise is not required. That is The Microsoft Way, isn't it? That's how Microsoft wins.
OK, let's talk about partial methods and how the LINQ data modeling tools use them. Looking at the code generated for the Northwind database by the LINQ to Entities modeling tool, for example, you'll see a C# class representing the Categories table that looks something like this:
public partial class Categories : EntityObject
{
private string _CategoryName;
partial void OnCategoryNameChanging(string value);
partial void OnCategoryNameChanged();
public string CategoryName
{
get { return this._CategoryName; }
set
{
this.OnCategoryNameChanging(value);
this._CategoryName = StructuralObject.SetValidValue(value, false, 15);
this.OnCategoryNameChanged();
}
}
}
The first time I looked at this kind of code a few months ago, I cocked my head like the puppy on the old RCA label staring into the phonograph as if to say, "What is this?" What is this odd use of the partial keyword on a method declaration? I had been tracking changes in the C# 3.0 specification but is it possible that I missed this new feature? Indeed, it seems so. Well, there's no time to learn like the present. So how do partial methods work?
A partial method like OnCategoryNameChanging and OnCategoryNameChanged shown above must be defined within a partial class. We know how partial classes work. Multiple parts of a larger class, typically defined in separate files, are assembled by the compiler into a single, cohesive class. So, does a partial method behave the same way? Can I define a single method in multiple parts and have the compiler coalesce the parts together? No, that's not what the term partial means in this case. How would the compiler know the order in which to apply the method parts, for example? With partial classes, ordering of discrete (and complete) member methods into the whole is not an issue. However, if methods were allowed to be defined in part, ordering would be of penultimate importance.
So, I suppose it's somewhat unfortunate for us that the keyword partial is used in this context. A partial method can't really be defined in parts. In deciding whether to reuse an existing keyword in this case or to create a new one, the language designers opted for the former. There is precedent for a decision like that. The abstract keyword may be used in C# to mark a class or a method, too. In Visual Basic .NET, the abstract concept applied to a class uses the keyword MustInherit, which is actually quite intuitive. The concept of an abstract method in Visual Basic .NET uses the keyword MustOverride, also self-documenting. But, in C# we just reuse the keyword abstract for both of these cases. The baggage of a bygone era, I suppose.
Using the abstract keyword precedent for illustration here has even more value. Looking at the definition of the OnCategoryNameChanging and OnCategoryNameChanged methods in the Categories class above, they appear to be very much like abstract methods. The partial methods have no implementation, i.e. no curly braces and no actual instruction code within. So how do they really work? Let's example another part of the Categories class in the same assembly, a part not written by the code generation tool:
public partial class Categories
{
partial void OnCategoryNameChanging(string value)
{
// examine the value and throw an exception
// to stop the change if necessary
// because of the way the CategoryName property's set
// accessor is written, this is like an AOP before advisor
}
partial void OnCategoryNameChanged()
{
// do whatever makes sense with the changed name
// because of the way the CategoryName property's set
// accessor is written, this is like an AOP after advisor
}
}
This part of the Categories class would ostensibly be written by a human being interested in intercepting the before and after events associated with a changing category name attribute. What the compiler does with this is really quite extraordinary. If the OnCategoryNameChanging and OnCategoryNameChanged methods had been declared as abstract, the Categories class would have also been abstract by definition. Going back the Visual Basic .NET keywords, a method that one MustOverride would necessarily be part of a class that one MustInherit. That makes sense, right?
But partial methods are not abstract, even though they appear to be quite similarly formed. In the case of an abstract method, the programmer is essentially saying that a derivation must exist that gives the method its shape. What a partial method implies instead is that the shape of a method may or may not exist at the programmer's discretion. If the programmer chooses to provide an implementation, then it can be called. If not, that's OK, too. This is really useful in the case of LINQ because we can establish an AOP-like advisory pattern around changing attributes (columns) very simply. If the programmer needs the before and/or after advice for some value, she can implement the partial methods to get it.
This led me to ponder, "What does the compiler emit to IL if one or both of the partial method advisors aren't implemented?" The answer is nothing. If you don't implement a partial method, the compiler simply emits no code wherever it is invoked. For unimplemented partial methods, it's as if the declaration never existed. Very efficient, indeed. So, partial methods give us some of the power of abstraction without forcing us to derive a whole new type to get it. Of course, there are limitations. Because partial class parts are limited to a single assembly, partial method implementations are also limited to a single assembly. Abstract classes don't have such a restriction.