Partial Class Pattern: Examples
Learn the Partial Class Pattern to split class definitions across multiple files. Examples in Python, Java, and JavaScript for code generation.
Note: This guide follows English-language naming conventions and terminology standards common in international development teams. Examples use English identifiers and comments to maximize compatibility across codebases and tooling.
Overview
The Partial Class Pattern splits a single class definition across multiple source files. At compile time, the fragments are merged into a single type. This separation allows auto-generated code (from designers, ORMs, or code generators) to live in one file while hand-written customizations live in another, without the risk of one overwriting the other.
While most associated with C# (partial class), the concept exists in other forms: Ruby modules reopen classes, Python allows monkey-patching, and Java’s default interface methods plus records achieve similar goals. The core benefit is organizational separation without runtime overhead.
When to Use
- For alternatives, see Marker Interface Pattern.
Use the Partial Class Pattern when:
- Code generators produce large boilerplate that should not be manually edited
- Hand-written business logic should be kept separate from scaffolded code
- Multiple developers work on different aspects of the same class simultaneously
- You want to organize a large class by concern (persistence, validation, serialization)
When to Avoid
- The class is small enough to fit comfortably in a single file
- The splits create circular dependencies or confusing navigation
- Language does not support partial types natively (workarounds add complexity)
- The pattern is used to hide that a class has grown too large (refactor instead)
Solution
C# (Native)
// AutoGenerated.cs — generated by a tool, do not edit
public partial class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
}
// Customer.Custom.cs — hand-written business logic
public partial class Customer
{
public bool IsValidEmail()
{
return Email?.Contains("@") ?? false;
}
public string GetDisplayName()
{
return $"{Name} <{Email}>";
}
}
Python
Python does not have partial classes, but classes can be reopened and monkey-patched:
from dataclasses import dataclass
# File: customer_base.py (auto-generated)
@dataclass
class Customer:
id: int
name: str
email: str
# File: customer_custom.py (hand-written)
def is_valid_email(self) -> bool:
return "@" in self.email if self.email else False
def get_display_name(self) -> str:
return f"{self.name} <{self.email}>"
# Reopen the class by attaching methods
Customer.is_valid_email = is_valid_email
Customer.get_display_name = get_display_name
# Usage
customer = Customer(id=1, name="Alice", email="alice@example.com")
print(customer.is_valid_email()) # True
print(customer.get_display_name()) # Alice <alice@example.com>
Java
Java does not have partial classes, but nested classes, default interface methods, and records with builders achieve similar separation:
// Auto-generated base
public class CustomerBase {
private final int id;
private final String name;
private final String email;
public CustomerBase(int id, String name, String email) {
this.id = id; this.name = name; this.email = email;
}
public int getId() { return id; }
public String getName() { return name; }
public String getEmail() { return email; }
}
// Hand-written extension via inheritance
public class Customer extends CustomerBase {
public Customer(int id, String name, String email) {
super(id, name, email);
}
public boolean isValidEmail() {
return getEmail() != null && getEmail().contains("@");
}
public String getDisplayName() {
return getName() + " <" + getEmail() + ">";
}
}
// Usage
Customer customer = new Customer(1, "Alice", "alice@example.com");
System.out.println(customer.isValidEmail());
System.out.println(customer.getDisplayName());
JavaScript
JavaScript allows extending prototypes at any time, achieving partial-class behavior:
// File: customerBase.js (auto-generated)
class Customer {
constructor(id, name, email) {
this.id = id;
this.name = name;
this.email = email;
}
}
// File: customerCustom.js (hand-written)
Customer.prototype.isValidEmail = function () {
return this.email?.includes('@') ?? false;
};
Customer.prototype.getDisplayName = function () {
return `${this.name} <${this.email}>`;
};
// Usage
const customer = new Customer(1, 'Alice', 'alice@example.com');
console.log(customer.isValidEmail()); // true
console.log(customer.getDisplayName()); // Alice <alice@example.com>
Explanation
The Partial Class Pattern solves a tooling and maintenance problem:
- Before: Code generators overwrite hand-written changes every time they run
- After: Generated code lives in one file, custom code in another; both compile to a single type
This is not about runtime behavior (there is no runtime difference between a partial and a monolithic class), but about source code organization and generator safety.
Variants
| Variant | Language | Mechanism |
|---|---|---|
| Partial class | C#, VB.NET | Native partial keyword |
| Reopen class | Ruby, Python | Monkey-patch / reopen at runtime |
| Mixin modules | Ruby, Python | Include modules into class |
| Default interface methods | Java | Interface methods with bodies |
| Partial method | C# | Generated stub, optional implementation |
What Works
- Never edit generated files. Mark them with
// <auto-generated>comments. - Use consistent naming.
Customer.generated.csandCustomer.custom.csmake intent clear. - Keep partials cohesive. Split by concern (serialization, validation), not arbitrarily.
- Document which file contains what. A class-level comment helps navigation.
- Regenerate in CI. Ensure generated files are always fresh and not manually modified.
Common Mistakes
- Splitting arbitrarily. Five partial files for a 100-line class is overkill.
- Creating circular dependencies. Partials should not depend on each other in confusing ways.
- Mixing generated and hand-written code in the same file. Defeats the purpose.
- Using partials to avoid refactoring. If a class needs ten partials, it may need extraction into smaller classes.
- Assuming thread safety from splitting. Partial classes have the same threading semantics as regular classes.
Real-World Examples
WinForms / WPF Designers (C#)
Visual Studio’s Windows Forms designer generates Form1.Designer.cs with auto-generated control initialization, while Form1.cs contains event handlers and business logic.
Entity Framework (C#)
EF’s scaffolding tools generate partial entity classes, allowing developers to add validation, computed properties, and business logic in separate partial files that survive re-scaffolding.
ASP.NET Core Razor
Razor pages compile markup (.cshtml) and code-behind (.cshtml.cs) into a single partial class, separating presentation from logic.
Advanced Topics
Scenario: Partial Class for Separating Responsibilities
// C#: partial class splits a class across multiple files
// File: Order.cs - Main model
public partial class Order {
public Guid Id { get; set; }
public string CustomerEmail { get; set; }
public List<OrderItem> Items { get; set; }
public decimal Total { get; set; }
public DateTime CreatedAt { get; set; }
}
// File: Order.Validation.cs - Validation logic
public partial class Order {
public bool IsValid() {
return Items.Count > 0 && Total > 0 && !string.IsNullOrEmpty(CustomerEmail);
}
public List<string> GetValidationErrors() {
var errors = new List<string>();
if (Items.Count == 0) errors.Add("Order must have items");
if (Total <= 0) errors.Add("Total must be positive");
if (string.IsNullOrEmpty(CustomerEmail)) errors.Add("Email required");
return errors;
}
}
// File: Order.Pricing.cs - Pricing logic
public partial class Order {
public void ApplyDiscount(decimal percentage) {
Total = Total * (1 - percentage / 100);
}
public void ApplyCoupon(string code) {
var coupon = CouponService.Validate(code);
if (coupon.IsValid) Total -= coupon.Amount;
}
public decimal CalculateTax(decimal rate) {
return Total * rate;
}
}
// File: Order.Serialization.cs - Serialization logic
public partial class Order {
public string ToJson() {
return JsonSerializer.Serialize(this);
}
public static Order FromJson(string json) {
return JsonSerializer.Deserialize<Order>(json);
}
}
Advantages and disadvantages of partial class:
| Aspect | Pros | Cons |
|--------|------|------|
| Organization | Separates responsibilities | Can fragment logic |
| Collaboration | Multiple devs on one class | Hard to locate code |
| Generation | Code-gen separate from manual | Merge conflicts |
| Maintenance | Smaller files | Fragmented view |
| Testing | Test separated by concern | Repeated setup |
Lessons:
- Partial class splits a class across multiple files
- Ideal for separating model, validation, pricing and serialization
- C# supports partial class natively; TypeScript does not
- In TypeScript, use composition or mixins instead of partial
- Do not overuse: if a class needs partial, it may be too large (SRP)
- Entity Framework uses partial to separate model from code-gen
### Is partial class available in TypeScript?
No, TypeScript does not support partial class. Alternatives: 1) Composition: separate into independent classes (OrderModel, OrderValidator, OrderPricer). 2) Mixins: add methods via functions. 3) Declaration merging: interfaces and namespaces merge, but classes do not. 4) Extension methods: use prototype or module augmentation. The best alternative in TypeScript is composition: each responsibility is a separate injected class. Related Resources
Mixin Pattern
Add reusable behavior to classes without inheritance by composing methods from shared objects into a target class.
PatternDecorator Pattern
Add new functionality to objects dynamically by wrapping them. A structural design pattern for flexible behavior extension.
PatternStrategy Pattern
Define a family of algorithms, encapsulate each one, and make them interchangeable. A behavioral design pattern for flexible behavior selection.
Frequently Asked Questions
- What is the difference between Partial Class and Inheritance?
- Partial classes are merged at compile time into a single type. Inheritance creates a runtime relationship between two distinct types. Partial classes cannot add fields that other partials depend on...
- Can partial classes have different access modifiers?
- No, all partial declarations must have the same access modifier and must be in the same assembly/namespace.
- How do I achieve partial classes in Java or Python?
- Java uses composition or inheritance; Python uses monkey-patching or mixins. Neither has true compile-time partials like C#.
- Can partial methods exist without an implementation?
- In C#, yes. A partial method declaration can exist in the generated file without an implementation in the custom file. The compiler removes the call site entirely if no implementation exists,...