Playing with Partial Types

I've been playing around with Partial Types in Visual Studio “Whidbey“ after a developer asked me how the Extract Interface refactoring will work when applied to partial types. First a quick primer on partial types -

  • Partial types lets you split the definition of a type (like a class) into multiple files. Visual Studio “Whidbey“ will, for example, divide VS designer generated code into one class and user written code into another.
  • When declaring a partial class, use the “partial“ keyword in the class definition: partial class MyPartialClass.
  • Partial types behave like just like regular types, except that the class is now divided into multiple files.
  • A partial type can be compiled without need all of its matching files, so multiple developers could divide a large class into working chunks and not interfere with each other (although you would obviously need the other partial class files if you reference code that is declared in another partial class).
  • Partial types are not limited to two files. In the example below, the class MyPartialClass is divided into three files - class1.cs, class2.cs and foo.cs.
  • If you're using the command line compiler, there is no messy linking, to use partial classes, just point to the files and add all the references you would need as if the class was declared in one file. Ex: “csc class1.cs, class2.cs, foo.cs“.
  • Visual Studio “Whidbey“ has full support for partial types (as you'll read below).

Refactoring partial classes

  • Invoking the Extract Interface refactoring will work the same for partial classes as it will for regular classes, meaning public non-static methods will be available to extract into an interface. For example, I ran the Extract Interface refactoring on MyPartialClass and the dialog window will list *both* overloads for the foo method, even though they are each declared in separate files. For convenience sake, I copy/pasted the extracted interface into Class1.cs.

Interfaces and partial classes

  • You can declare the interface in one partial class, and implement the interface across multiple partial classes. If you do not fully implement the interface in all of the partial classes, you will get an error saying that you haven't fully implemented the interface, which is again the same behavior as if the class was declared in one file. In the example below, the file class2.cs declares the IPartialClass interface and the IPartialClass interface is implemented in multiple files - class2.cs and foo.cs.

IntelliSense for variables declared in partial classes

  • A variable declared in one partial class is available through IntelliSense across all of the partial classes (assuming correct scope). In the example below, Class1.cs declares a variable, private string s, and both the methods in the files Class2.cs and foo.cs can use this variable.

Method overloads in partial classes

  • You can split method overloads into separate partial classes, but, just like a regular class, the method signature must be different for each overload our you'll get an error saying that you have already defined the method in the given class. In the example below, two partial classes, class2.cs and foo.cs each define a method named foo, but with different method signatures - foo(string PrintString) & foo().
  • IntelliSense fully understands method overloads even if they are declared in multiple files. In the example below, Class1.cs has a class named TestClass that calls the overloaded method foo. Using IntelliSense in the Main() method, the developer will see both method overloads just like a regular class. 

 

Class1.cs

using System;

interface IPartialClass

{

     void foo(string s);

     void foo();

}

 

 

partial class MyPartialClass

{

     private string s = "Hello World";

}

 

 

class TestClass

{

     [STAThread]

     static void Main(string[] args)

     {

           MyPartialClass MyClass = new MyPartialClass();

MyClass.foo("Print this");

MyClass.foo();

Console.ReadLine();

    

     }

}

 

Class2.cs

using System;

public partial class MyPartialClass : IPartialClass

{

public void foo(string PrintString)

{

Console.WriteLine(PrintString + " " + s);

}

}

 

foo.cs using System;

 

partial class MyPartialClass

{
    public void foo()

     {
           Console.WriteLine(s);
     }
}