Skip to Content
Course content

27: Partial Classes and Methods

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Imagine you're designing a house. You have a structural engineer who handles the "bones"—the load-bearing walls, the plumbing, and the electrical wiring. Then you have an interior designer who handles the "feel"—the paint colors, the furniture layout, and the lighting fixtures. They aren't building two different houses; they're both working on the exact same house. But for the sake of sanity, they each have their own set of blueprints. If the structural engineer needs to move a pipe, they don't want to accidentally smudge the designer's carefully chosen wallpaper swatch.

That is exactly what partial classes do in C#. They allow you to split a single class definition across multiple files. When the compiler runs, it gathers all those pieces and stitches them together into one single class. You'll most often see this when you're using tools that auto-generate code. I've spent plenty of hours fighting with generated code in the past, and partial classes are the only reason we don't lose our minds when a tool decides to "refresh" a file and overwrite everything we manually wrote.

Splitting the logic across files

Let's say you have a UserAccount class. In a real-world app, a tool might generate the properties based on your database schema. You don't want to touch that file because if you change the database and regenerate the class, your manual changes vanish. Instead, you mark the class as partial.

// File: UserAccount.Generated.cs
// This file is managed by a tool. Don't touch it!
public partial class UserAccount
{
    public int Id { get; set; }
    public string Username { get; set; }
    public string Email { get; set; }
}

Now, you can create a second file for your actual business logic. Since it's also marked partial, the compiler knows it belongs to the same class.

// File: UserAccount.Logic.cs
// This is where we put the stuff we actually care about.
public partial class UserAccount
{
    public bool IsValidEmail()
    {
        return Email.Contains("@") && Email.Contains(".");
    }

    public string GetDisplayName()
    {
        return $"{Username} ({Email})";
    }
}

To the rest of your program, UserAccount is just one class with five members. It doesn't know (or care) that the code is physically located in two different files.

Creating hooks with partial methods

Partial methods are a slightly more specialized tool. Think of them as "hooks." They allow the generated part of a class to say, "I'm going to do something here, and if the human wants to add extra logic at this specific moment, they can. If they don't, just ignore this call."

Here is how that looks in practice. The generated code defines the method signature but provides no body.

// File: UserAccount.Generated.cs
public partial class UserAccount
{
    // This is the declaration. It's like a placeholder.
    partial void OnEmailChanged();

    public void UpdateEmail(string newEmail)
    {
        this.Email = newEmail;
        // We call the hook here.
        OnEmailChanged();
    }
}

Now, in your logic file, you can choose whether or not to implement that method. If you don't write the implementation, the C# compiler is smart enough to completely remove the call to OnEmailChanged() from the final binary. There's zero performance hit for a hook you didn't use.

// File: UserAccount.Logic.cs
public partial class UserAccount
{
    // We decided we actually want to do something when the email changes.
    partial void OnEmailChanged()
    {
        Console.WriteLine($"Log: Email for user {Username} was updated.");
    }
}

I personally find this pattern incredibly useful for logging or validation without cluttering the "core" generated logic of a system. Just remember: partial methods must return void and cannot have access modifiers (like public or private) if they are to be omitted by the compiler when not implemented.




📋 Practical Task

Building a Partial Payment Processor

You are building a payment system where the API communication code is generated by a third-party library, but the logging and validation logic must be written by you. Your goal is to separate these concerns using partial classes and methods.

  • Create a partial class named PaymentProcessor.
  • In the "generated" portion of the class, create a method ProcessPayment(decimal amount). Inside this method, call a partial method named OnPaymentProcessed before printing "Payment of {amount} sent to API" to the console.
  • In the "logic" portion of the class (the part you are implementing), provide the implementation for OnPaymentProcessed. This method should print "Log: Transaction recorded in local database" to the console.
  • In your Main method, instantiate the PaymentProcessor and call ProcessPayment(99.99m).

Verify that both the log message and the API message appear in the console, proving that the two partial pieces of the class are working as one.

Rating
0 0

There are no comments for now.

to be the first to leave a comment.