Partial Methods - I Object?
No, not partial classes. Partial methods. As Wes talks about in his latest post on language enhancements in Orcas, partial methods are another new C# language feature that allows you to define the signature of a method in one part of a partial class and the method implementation in another part. For example, consider the basic entity class "SomeEntity".
1: public partial class SomeEntity
2: { 3: private string _someAttribute;
4:
5: public string SomeAttribute
6: { 7: get { return _someAttribute; } 8: set { 9: Validate(this, "SomeAttribute", value);
10: OnSetting(this, "SomeAttribute", value);
11: _someAttribute = value;
12: OnSet(this, "SomeAttribute");
13: }
14: }
15:
16: partial void OnSet(SomeEntity someEntity, object p);
17:
18: partial void OnSetting(SomeEntity someEntity, string p, object value);
19:
20: partial bool Validate(SomeEntity someEntity, string p, object value);
21: }
On cursory inspection, this class appears like any regular entity-style class. However, check out lines 16, 18 and 20. What we see here is a method signature prototype - much like what we would see in an abstract base class. However, rather than using the abstract mechanism to facilitate extension, we are using a new keyword (well, new in this context anyway), "partial", to describe our extension mechanism. In order to extend any one of the 3 methods declared as partial, a developer simply creates another part of the partial class and implements a method using the partial keyword and the same method name. I'm hesitant to make any assertions about constraints on the signature as I have yet to get the Orcas beta 2 bits and do more detailed testing. However, if I read Wes' blog correctly, I think that there may be some room for parameter redefinition.
1: public partial class SomeEntity
2: { 3: partial void OnSet(SomeEntity someEntity, object p){ 4: //log that the property was successfully set
5: }
6: }
So, after this very basic example, the obvious question - why? I've heard a lot of answers to this question. However, the one rising to the top is that partial methods were added in order to provide performance optimization to code generators - most notably, Linq to SQL and Linq to DataSet. I've also heard partial methods described as a way of doing compile-time aspect weaving, but let's deal with the performance optimization characteristics in this post.
Wes has described the primary purpose of partial methods as a way to do lightweight event handling. I am really hesitant to use the phrase "event handling" as I think that partial methods are more of an alternative to virtual method calls than they really are to events. Therefore, I'm going to go out on a limb and say that partial methods are a more lightweight means of composing functionality at the method level. For you patterns folks, it is a performance optimization around the template pattern. How is it optimized? Because in the current world, where the pattern is implemented through virtual methods, the compiler calls a virtual method regardless of whether or not that method has been extended in a derrived class. In the world of partial methods, the compiler checks to see whether the partial method being called has a concrete implementation defined and, if it does not, the compiler does not generate a call to that method. Therefore, given our 2 examples above, if we reverse-engineered our compiled assembly, we would see that the set accessor for the SomeAttribute property looked like the following.
1: public string SomeAttribute
2: { 3: get { return _someAttribute; } 4: set { 5: _someAttribute = value;
6: OnSet(this, "SomeAttribute");
7: }
8: }
So my general thinking on this is actually very similar to my general thinking on extension methods. It seems to me like both were added as general language features, but added to support a very specific use case - Linq. Now, that doesn't mean that I'm suggesting that they have no uses outside of Linq. It does mean, however, that I think that they should have VERY limited use out there in the general application development universe, as I believe they have the capacity to do a great deal of harm.
Why do I believe this? Because fundamentally, partial methods seem to take away from the expressiveness of code and add greater potential for side effects. The more time I spend thinking about partial methods, the less concerned I am with the first point. For example, considering our set accessor, when using partial methods we would never actually know whether our method call would be called called - as the compiler would determine this based on the definition of the other class parts. Initially, I thought that this was a really bad thing - until I thought more about how the template pattern was implemented by using virtual methods - and then thought about how it could be implemented with an interpreted language like JavaScript. In both cases, the expectation for the developer is essentially the same - "If I have a custom implementation of the method, run it; otherwise, if there is a default implementation, run that; otherwise, do nothing." With virtual methods, however, there was no semantic to express "do nothing" - you had to create an empty method body. Therefore, partial methods actually allow for a more expressive grammar.
That does not outweigh the badness of the second danger, however. With virtual methods, you at least have some determinism around the call order. For example, if I overrode a method in a class, I could sleep soundly at night knowing that my overridden method would be called every time it was called on my class. If I did not override a method, I could have that same level of confidence knowing that my base class method would be called. With partial classes, there is no 1:1 parent:child relationship - there is no limitation on the number of class parts that can be created - and the same is true of partial methods. There is then (IMHO) a huge risk of unintentionally introducing side effects that are really difficult to debug.
In conclusion, one of the questions I would raise is this. If partial methods were essentially a language supplied performance optimization for people writing code generators, why make it a language feature at all? Why not make it something implicit in the compiler - similar to how the C compiler automatically inlines simple methods?
I am currently the Editor-in-Chief for MSDN Magazine. I joined Microsoft in 2006 as a product planner with the certification team at Microsoft Learning. Prior to that, I spent my career as a developer and later as an architect. My main technology passions include pretty much anything on language theory, agile development, and service-oriented architecture.