C# 3.0 partial methods - What, why and how? Saturday, July 28, 2007 5:46 AM bart

As you've heard by now, Orcas beta 2 (or should I start to talk about VS2008 and .NET Framework 3.5 instead?) has hit the web. If you didn't know yet, here are a few pointers:

On to the real stuff. In this post I want to talk about a new C# 3.0 feature, called partial methods, that's introduced in the beta 2 release. Likely you already know about partial classes, which were added in the 2.0 timeframe. So, what's in a name? In short, partial classes allow you to split the definition of a class across multiple files, or alternatively you could think about it as a code compilation unit separated over multiple files. The reason for the existence of this feature is - primarily - to provide a nice split between generated code and user code, as in the Windows Forms Designer that generates its code in a separate file, while developers have almost (you should delete the initialization call in the ctor) full control over the form's other code file (the one where the event handlers find a place to live).

Partial methods are methods living in partial classes which are marked as partial. Their existence also stims from the world of code generation - although it's likely to be useful outside this scope too - and allows to compile efficient code while allowing end-user extensions to the class by implementing a method. I know it's a little vague, so let's take a look at a more concrete sample. Over here I have a simple console app:

using System; partial class PartialMethods //Part 1

{

static void Main()

{

Do();

} static partial void Do();

} partial class PartialMethods //Part 2

{

static partial void Do() {}

}

I've defined both parts of the partial class in the same file, but in real scenarios you'd have the two parts in separate files of course. So, what's happening in here? In part 1 of the class definition, I've declared the Do method as partial. Notice it's a static but that doesn't need to be the case, it works in a similar fashion with instance methods. Partial methods don't take an implementation body, it's just a declaration, much as you're used to in interfaces or abstract classes. In part 2 of the class definition, I've 'implemented' the partial method, for demo purposes just with an empty body. In reality, the complete definition from above is equal to:

using System; class PartialMethods

{

static void Main()

{

Do();

} static void Do() {}

}

If you take a look at the IL code:



(Notice the new version number on the C# compiler)

you can see that the Main method contains a call to the Do method. But what if we'd omit the definition of the partial method, like this:

using System; partial class PartialMethods

{

static void Main()

{

Do();

} static partial void Do();

}

In other words, what if no part of the partial class provides a method body for Do? Then, the following happens:

Right, no single trace of Do at the caller's side. It goes even further than that: all of the parameters evaluation is omitted too: try to guess what the following will print:

using System; partial class PartialMethods

{

static void Main()

{

int i = 0;

Console .WriteLine(i);

Do(i++);

Console .WriteLine(i);

} static partial void Do( int i);

}

Right, if there's an implementation of Do, you'll see this piece of code in Main:

The region indicates by the red rectangle is the piece of IL code that's part of the Do(i++) method call. Ignore the nop instructions as I'm generating non-optimized debuggable code (for the unaware, nop instructions are inserted in debug builds to allow to set breakpoint on various code elements, including lines with just curly braces; in the code above, the whole method body is surrounded with two nops, one for both Main method body curly braces). I you don't have an implementation somewhere, you'll just see this:

There's just a nop left, and the i++ side-effect's code is gone too. In other words, you can't tell what the code will print if you don't know whether or not there's a method body somewhere. Notice this is somewhat similar to conditional compilation with the ConditionalAttribute:

using System;

using System.Diagnostics; class Program

{

static void Main()

{

int i = 1;

Console .WriteLine(i);

Do(i++);

Console .WriteLine(i); } [ Conditional ( "BAR" )]

static void Do( int i)

{

}

}

As you can see, the caller's IL is very similar:

unless you define BAR (e.g. using #define or using the /define:BAR csc command line switch):

Notice the use of System.Diagnostics.CondtionalAttribute isn't limited to partial classes. The most known use of this attribute is likely the Debug class, which has static methods (such as Assert) that are marked with Conditional["DEBUG"]: if you're running a non-debug build, no Debug.* calls are left in the code. There are a few core differences however; start by taking a look at the callee. No matter how the code is built, the Do method definition will be there:



Tip: try to read the serialized custom attribute's data; it says: 01 00 03 42 41 52 00 00, which really means "the three following bytes are B A R" (consult ECMA 335 for full details on custom attributes in IL).

In case of partial methods, it's really partial: there can be calls to 'non-implemented' methods (at the surface it looks as if the method signature is still there, so it feels like a non-implemented method, although in the resulting code there's just nothing left from a partial method if no method body is found).

Of course, there are a few limitations in using partial methods. First of all, partial methods are always private. The following won't compile (error CS0750: A partial method cannot have access modifiers or the virtual, abstract, override, new, sealed, or extern modifiers):

using System; partial class Bar

{

public partial void Foo();

}

The reason for this is simple: if no single bit of code is generated, even not at the callee side (i.e. there's no metadata describing a "partial method declaration"), the method shouldn't be visible outside the scope of the class since external callers don't know whether the method really exists or not. For the same reason, you can't create a delegate to a partial method (CS0762: Cannot create delegate from method %1 because it is a partial method without an implementing declaration):

using System;

using System.Threading; partial class Program

{

static void Main()

{

new Thread ( new ThreadStart (Worker)).Start();

}



partial void Worker();

}

If you have an implementing declaration however, the code will compile fine (but in such a case you're intentionally specifying an implementation, so you won't have much benefit of declaring the method as partial).

Another limitation is that the method needs to have the void return type. The following won't compile (CS0766: Partial methods must have a void return type):

using System; partial class Bar

{

partial int Foo();

}

Again, the reason is straightforward. If we don't know for sure there will be a method implementation, how can we possibly know what the return value should be?

int i = new Bar().Foo();

int j = i * 2; //???

Similarly, out parameters are not allowed (error CS0752: A partial method cannot have out parameters):

using System; partial class Bar

{

partial void Foo( out int i);

}

for the same reason. In general I tend to avoid out parameters in most cases, especially for the public interface of an API design. The main reason for this is the lack of composability when working with such APIs: calling a method with out params requires users to define a variable first, prior to making the call. A functional style (functions, in math terms, do have a single output value - which of course can be a composed type) is much easier to use, but it might require a bit of additional work to create a suitable return type that wraps all of the to-be-returned values. Ref parameters are allowed nevertheless:

using System; partial class Bar

{

partial void Foo( ref int i);

}

In reality, out and ref are the same under the covers, but the compiler enforces different checks: out params must be assigned (CS0177) as part of the method body, ref params don't need to do so; at the caller's side, ref params should be assigned prior to making a call (CS0165).

Obviously, there shouldn't bee more than one declaration and/or implementation:

using System; partial class Bar

{

static void Foo();

static void Foo(); //CS0756: A partial method may not have multiple defining declarations

} partial class Bar

{

static void Foo() {}

static void Foo() {} //CS0757: A partial method may not have multiple implementing declaration s

}

The code fragment above sets the vocab right: defining declaration and implementing declaration. Also, you can't have an implementing declaration if there isn't a defining declaration (CS0759).

Where does Orcas eat its own dogfood? LINQ to SQL is one place where you see partial methods in action. In the illustration below, I've created a LINQ to SQL Classes ".dbml" file:

and I created a mapping for some SQL Server 2005 table from TFS:

Now, when you take a look at the generated code in the corresponding designer file, you'll see a region marked as "Extensibility Method Definitions". This one contains a bunch of partial methods:

I've indicated one pair of a partial method definition and an invocation, as used in an column mapping auto-generated property, in this case for a field called "AssemblySignature" (don't ask me about the TFS db schema):

For each such property, the setter has two "guards" that call a generated partial method. If you don't do anything else than just generating the entity classes, these calls are non-existing because there's only a defining declaration without an implementing one. However, these inserted calls are really extension points for the end-users of the generated code; in this case for LINQ to SQL, these allow to add business logic validation rules, e.g. as follows:

Just define another part of the partial class and type "partial". IntelliSense will jump in and tell you about the partial methods that you can provide an implementing declaration for. Select it and press enter to implement the method:

Once you've implemented such a method, the compiled code will contain the calls to it in the property setters, and you were able to do so without touching the generated code (which you shouldn't do, because it will be overwritten sooner or later). Notice one could get similar results by using events, but these cause runtime overhead that can't be eliminated. A sample with events is shown below (sorry to stress Gen 0 of your GC):

using System;

using System.Diagnostics;

#region Consumer

class Program

{

static void Main()

{

Stopwatch sw = new Stopwatch ();

sw.Start();

for ( int i = 0; i < 1000000; i++)

{

Bar b = new Bar ();

b.Callback += delegate { /* Console.WriteLine("ET calling home."); */ };

b.Do();

}

sw.Stop();

Console .WriteLine(sw.Elapsed.Milliseconds);

}

}

#endregion

#region Provider

delegate void Callback();

class Bar

{

public event Callback Callback;

public void Do()

{

if (Callback != null )

Callback();

}

}

#endregion

Execution time of this piece of code is around 72 ms on my Orcas Beta 2 VPC. If you drop the callback event registration on the consumer's side, it's about 17 ms. Below is an alternative using partial methods:

using System;

using System.Diagnostics;

#region Consumer

class Program

{

static void Main()

{

Stopwatch sw = new Stopwatch ();

sw.Start();

for ( int i = 0; i < 1000000; i++)

{

Bar b = new Bar ();

b.Do();

}

sw.Stop();

Console .WriteLine(sw.Elapsed.Milliseconds);

}

}



partial class Bar

{

partial void Callback()

{

/* Console.WriteLine("ET calling home."); */

}

}

#endregion

#region Provider

partial class Bar

{

partial void Callback();



public void Do()

{

Callback();

}

}

#endregion

Notice the consumer's side has been extended a little bit. In order to "register to the event" you'll need to write a partial method implementing declaration. Executing this piece of code costs about 12 ms, with the callback in there (6 times faster). If you drop the callback (i.e. no "partial class Bar" thing in the Consumer region), perf will be about the same (though, in theory, slightly faster). However, observe the difference with using events: the whole callback overhead through delegates is worse than having a "regular" method call in place. Of course, you can't compare both approaches on a general level since events and delegates are much richer constructs (just to name one difference: partial methods should be private, so you can't cross the boundary of a class definition, while events can be exposed as public members).

I guess I shouldn't forget to mention that VB 9.0 has partial methods as well. Although it looks a bit like a zebra in the code editor <g>, it works similarly:

One unfortunate thing about all of this is the lack of CodeDOM support for partial methods (it supports partial classes though). So, you'll have to rely on a CodeSnippetTypeMember instead of a CodeMemberMethod to create the partial methods, just using (constant) string values. The reason for this discrepancy is the fact that CodeDOM is part of the v2.0 FX assemblies which don't change in .NET FX 3.5.

Pretty cool, isn't it?