Saturday, July 28, 2007 5:46 AM bart

C# 3.0 partial methods - What, why and how?

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:

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

image

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:

image

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:

image

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:

image

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:

image

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

image

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:

image
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 declarations
}

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:

image

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

image

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:

image

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):

image

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:

image

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:

image

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:

image

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?

Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

Filed under:

Comments

# re: C# 3.0 partial methods - What, why and how?

Saturday, July 28, 2007 9:11 AM by TraumaPony

Bah. If  the framework gets new features, there should be CodeDOM support for it.

# re: C# 3.0 partial methods - What, why and how?

Saturday, July 28, 2007 1:30 PM by Frank Quednau

...very much so! Looks quite useful. Thanks for the rundown.

# re: C# 3.0 partial methods - What, why and how?

Saturday, July 28, 2007 2:56 PM by bart

Hi TraumaPony,

I do understand you concerns. However, for code-generation there are quite some options to choose from. Making CodeDOM too heavy would reduce its (mostly) language-indepent characteristic, certainly now that languages start to evolve quickly (LINQ syntax, lambdas, XML literals in VB 9, ...)

First of all, notice that CodeDOM isn't complete because it just covers basic concepts that most languages do expose; an obvious example is to generate code for iterators using the yield keyword or even something "as trivial as" a foreach loop construct. There are many such things that aren't covered by CodeDOM, it's a matter of finding a good set of things that can be translated into various target languages. That's why God invented the concept of raw literal code snippets in order to escape from such issues; however, this will likely require you to make a switch in your code to distinguish between the languages you're targeting (if VB ... else if C# ... else Oops!).

An alternative approach to code-generation is to use simple and straightforward string replacements. For example, the built-in VS templates - as you can find in %PROGRAMFILES%\Microsoft Visual Studio 8\Common7\IDE\ItemTemplates\CSharp\1033 in case of C# - are based on such a replacement mechanism driven by the item template's settings (see the vstemplate XML file). This is particularly useful if you can really define a template with a few customization holes in it. In contrast to CodeDOM this approach doesn't hide the generated code in a large chunk of code-generation code.

Last but not least, there's the approach taken by the Visual Studio DSL tools that's inspired on plain old ASP processing. Templates can be written using plain text, mixed with instructions wrapped by <# ... #>, e.g.:

class People

{

<#

foreach (Person person in this.Model.Persons) {

#>

    public string <#=person.Name#> { get; set; }

<#

}

#>

}

Hope this helps,

-Bart

# University Update-C#-C# 3.0 partial methods - What, why and how?

Pingback from  University Update-C#-C# 3.0 partial methods - What, why and how?

# C# 3.0中的分部方法

Monday, July 30, 2007 6:49 AM by Anders Liu

在看C#语言的What's New时,突然发现新特性列表的最后,多出了一个“Partial Method Definitions ”,但并不像其他新特性一样有超链接链接到其说明。上网搜索了一下,关于分部类型的信息非常少。尤其是中文信息,只有CSDN的 周融 在其《C# 3.5 语言在 Visual Studio Orcas Beta 1 上的新增功能(二) 》一文的最后提到了这个分部方法,但没有进一步说明。英文技术文章中,倒是有两篇不错的:http://blogs.msdn.com/wesdyer

# Partial methods

Friday, August 03, 2007 2:44 AM by Daniel Moth

Partial methods

# C++,C#, .NET, ADO.NET, SQL, Visual Studio GURU &raquo; Blog Archive &raquo; Partial Methods (Parcijalne Metode - novine u C# 3.0)

Pingback from  C++,C#, .NET, ADO.NET, SQL, Visual Studio GURU  &raquo; Blog Archive   &raquo; Partial Methods (Parcijalne Metode - novine u C# 3.0)

# C++,C#, .NET, ADO.NET, SQL, Visual Studio GURU &raquo; Blog Archive &raquo; Partial Methods (Parcijalne Metode - novine u C# 3.0)

Pingback from  C++,C#, .NET, ADO.NET, SQL, Visual Studio GURU  &raquo; Blog Archive   &raquo; Partial Methods (Parcijalne Metode - novine u C# 3.0)

# C# 3.0 partial methods - What, why and how?

Wednesday, September 26, 2007 2:11 PM by DotNetKicks.com

You've been kicked (a good thing) - Trackback from DotNetKicks.com

# 10 Hot ASP.NET Tips and Tricks - 10/28/2007

Friday, September 28, 2007 3:01 AM by 10 Hot ASP.NET Tips and Tricks - 10/28/2007

Pingback from  10 Hot ASP.NET Tips and Tricks - 10/28/2007

# 3 Links Today (2007-09-29)

Saturday, September 29, 2007 8:20 AM by 3 Links Today (2007-09-29)

Pingback from  3 Links Today (2007-09-29)

# C# 3.0 : Partial Methods

Thursday, December 13, 2007 1:50 PM by Wriju's BLOG

C# 2.0 and Partial class, in one of the amazing features to work with one class separated in multiple

# C# vNext Revisited

Wednesday, January 30, 2008 5:40 PM by Matthew Podwysocki's Blog

I often rethink or have additions to my posts. This topic of what's coming in C# vNext is definitely

# LINQ - introduction

Sunday, April 06, 2008 6:46 AM by stelian

What and Why is LINQ? LINQ , stands from &quot;Language Integrated Query&quot;, so is a thing which is

# C# 3.0 Feature Focus – Link Collection

Saturday, August 09, 2008 7:13 AM by B# .NET Blog

Collecting a few of my posts for easy quick reference: C# 3.0 Feature Focus - Part 1 - Local Type Inference

# Partial Methods &laquo; Ctrl+Shift+B

Wednesday, April 08, 2009 7:48 AM by Partial Methods « Ctrl+Shift+B

Pingback from  Partial Methods &laquo; Ctrl+Shift+B

# Partial Methods to the rescue

Tuesday, August 04, 2009 9:41 AM by Frederick Chapleau .NET Tip of the Day

If you already know partial classes, you should take a look at partial method. This is far from basic

# Partial Methods (Parcijalne Metode &#8211; novine u C# 3.0) &laquo; Bahrudin Hrnjica Web Page

Pingback from  Partial Methods (Parcijalne Metode &#8211; novine u C# 3.0) &laquo; Bahrudin Hrnjica Web Page

# Some emails in qalmchip &laquo; Shahzad&#039;s Weblog

Sunday, November 08, 2009 5:31 AM by Some emails in qalmchip « Shahzad's Weblog

Pingback from  Some emails in qalmchip &laquo; Shahzad&#039;s Weblog

# C # 3.0 division a method

Sunday, June 12, 2011 4:54 PM by C # 3.0 division a method

Pingback from  C # 3.0 division a method

# Why is wrong code generated by Linq-to-SQL, but there&#8217;s no error when compiling - Programmers Goodies

Pingback from  Why is wrong code generated by Linq-to-SQL, but there&#8217;s no error when compiling - Programmers Goodies

# C#3.0??????????????? - ??????????????? - ?????????

Thursday, April 05, 2012 11:42 AM by C#3.0??????????????? - ??????????????? - ?????????

Pingback from  C#3.0??????????????? - ??????????????? - ?????????

# Partial Methods in C# | Adventures in Coding

Wednesday, April 18, 2012 6:47 PM by Partial Methods in C# | Adventures in Coding

Pingback from  Partial Methods in C# | Adventures in Coding

# Calling Partial Methods in C# | Search RounD

Wednesday, March 05, 2014 6:49 PM by Calling Partial Methods in C# | Search RounD

Pingback from  Calling Partial Methods in C# | Search RounD