What are partial classes in C# and why do we use them?

Published: Monday 9 September 2024

A partial class can be used to split functionality across multiple files, each with the same namespace and class name.

In Visual Studio, if you were to create a class with a file name of MyClass.cs, it would generate a file with a MyClass class.

C# coding challenges

C# coding challenges

Our online code editor allows you to compile the answer.

Furthermore, if you were to create a class with a file name of MyClass.Methods.cs, it would also generate a file with a MyClass class.

This would generate the following exception:

CS0101: The namespace 'x' already contains a definition for 'MyClass'

You can't have two classes of the same namespace and class name. 

That is unless you mark them as partial.

// MyClass.cs
public partial class MyClass
{
}

// MyClass.Methods.cs
public partial class MyClass
{
}

When you have multiple partial classes of the same namespace and class name, the compiler will merge all members from each of the partial classes into one single class.

This can be demonstrated by adding a property into the partial class in the MyClass.cs file, and then using it in a method inside the partial class within the MyClass.Methods.cs file.

// MyClass.cs
public partial class MyClass
{
	public bool Ok { get; set; }
}

// MyClass.Methods.cs
public partial class MyClass
{
	public bool IsItOk()
	{
		return Ok;
	}
}

The partial keyword also works in a struct or an interface.

The rules around partial classes

Because the compiler will merge all the members for each of the partial classes into one single class, we need to follow the basic rules of a C# class.

All classes must be marked as partial

All partial classes of the same namespace and class name must include the partial keyword before the class declaration. If they don't, the following exception will appear:

CS0260: Missing partial modifier on declaration of type 'MyClass'; another partial declaration of this type exists

Where the partial keyword appears

The partial keyword must appear before the keyword class (or struct or interface if you are using that). If you try to add abstract after the partial keyword, the following exception will be thrown:

CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type.
// MyClass.cs
// Throws exception
public partial abstract class MyClass
{
	public bool Ok { get; set; }
}

Namespaces must be the same

Namespaces must be the same for each of the partial classes.

If they don't, the compiler will see it as a different class and will throw an exception if you are using any of the members from a partial class that has a different namespace.

Access modifiers must be the same

Access modifiers must be the same for all of the partial classes.

If you were to change one of the partial classes to internal but leave the other one as public, the following exception would be thrown:

CS0262: Partial declarations of 'MyClass' have conflicting accessibility modifiers
// MyClass.cs
// Throws exception
internal partial class MyClass
{
	public bool Ok { get; set; }
}

// MyClass.Methods.cs
public partial class MyClass
{
	public bool IsItOk()
	{
		return Ok;
	}
}

Abstract and sealed classes

If one of the partial classes is marked as abstract, the class is an abstract class even if it's not declared on any other partial classes. This rule also applies to the sealed keyword.

In this instance, if you tried to initalise a partial class marked as abstract, it would throw a compile exception.

// MyClass.cs
public abstract partial class MyClass
{
	public bool Ok { get; set; }
}

// MyClass.Methods.cs
public partial class MyClass
{
	public bool IsItOk()
	{
		return Ok;
	}
}

// Program.cs
var a = new MyClass(); // Throws exception.

Attributes follow the same rule

Attributes will follow the same rule as the abstract and sealed keywords.

For example, if you were to mark one of the partial classes with the [Obsolete] attribute, the class would be declared as obsolete.

// MyClass.cs
[Obsolete]
public partial class MyClass
{
	public bool Ok { get; set; }
}

// MyClass.Methods.cs
public partial class MyClass
{
	public bool IsItOk()
	{
		return Ok;
	}
}

// Program.cs
var a = new MyClass(); // Obsolete warning

You can only inherit one class

You can only inherit one class into a partial class. You will get this exception if you try to inherit more:

CS0263: Partial declarations of 'MyClass' must not specify different base classes

This is the same even if you separate the inheritance into each of the partial classes. The resulting exception will still be the same.

// MyBaseClass.cs
public class MyBaseClass {

}

// MyBaseClass2.cs
public class MyBaseClass2 {

}

// MyClass.cs
public partial class MyClass : MyBaseClass
{
	public bool Ok { get; set; }
}

// MyClass.Methods.cs
public partial class MyClass 
	: MyBaseClass2 // This results in an exception.
{
	public bool IsItOk()
	{
		return Ok;
	}
}

You can implement multiple interfaces

Like with a normal C# class, you can implement multiple interfaces into a partial class. 

And it doesn't matter where they are implemented. They can all be implemented in one of the partial classes or they can be spread out across all the partial classes.

As long as any of the declarations in the interface are implemented into one partial class, the application will compile.

// IBase.cs
public interface IBase {
	void MyMethod();
}

// IBase2.cs
public interface IBase2 {
}

// MyClass.cs
public partial class MyClass : IBase
{
	public bool Ok { get; set; }
}

// MyClass.Methods.cs
public partial class MyClass : IBase2
{
	public bool IsItOk()
	{
		return Ok;
	}
	
	public MyMethod() {
		// Will compile despite this method being implemented in IBase
	}
}

Constructors must have different signatures

As per the rules in a C# class, you can't have multiple constructors of the same signature even if they appear in different partial classes.

If you do, this exception will be thrown:

CS0111: Type 'MyClass' already defines a member called 'MyClass' with the same parameter types
// MyClass.cs
public partial class MyClass
{
	public MyClass() {
	
	}

	public bool Ok { get; set; }
}

// MyClass.Methods.cs
public partial class MyClass
{
	public MyClass() {
		// Already a parameterless constructor in MyClass.cs, so throws an exception.
	}

	public bool IsItOk()
	{
		return Ok;
	}
}

Partial members

It's also possible to add partial members to a partial class.

This can be handy if a source generator was to add a partial method, meaning you can add the implementation for that method into another partial class.

In this example, one of the partial classes has added a partial method called Abc without an implementation. You can add this implementation into another partial class as long as the namespace and class match.

// MyClass.cs
public partial class MyClass
{
    partial void Abc();
}

// MyClass.Methods.cs
public partial class MyClass
{
    partial void Abc()
    {
		// Add implementation in here.
    }
}

Why use partial classes in the first place?

Partial classes are good if you have multiple developers working on the same class. One developer could work on one file, whilst another could work on another file.

This could mitigate merge conflicts when committing the files into source control.

It can also allow you to add additional functionality to files that are source generated.

Watch our video to see an example of a source generated file and how you use it to add additional functionality.

The video also recaps on the rules around partial classes and gives examples of the exceptions that might occur when you work with partial classes.