partial class

황현중·2025년 12월 1일

1. partial class 한 줄 정의

partial class = “하나의 클래스를 여러 파일로 나눠서 정의할 수 있게 해주는 문법”

보통은 “클래스 하나 = 파일 하나”처럼 생각하기 쉬운데, C#에서는 하나의 클래스를 여러 .cs 파일에 나눠서 적을 수 있다.
나눠져 있는 코드들은 컴파일할 때 컴파일러가 전부 합쳐서 하나의 클래스로 만들어 준다.

간단 예제

예를 들어, 아래처럼 두 파일이 있다고 해 보자.

Person.cs

public partial class Person
{
    public string Name { get; set; }

    public void SayHello()
    {
        Console.WriteLine($"안녕, 나는 {Name}");
    }
}

Person.Address.cs

public partial class Person
{
    public string Address { get; set; }

    public void PrintAddress()
    {
        Console.WriteLine($"주소: {Address}");
    }
}

이 두 파일은 컴파일될 때 이렇게 하나의 Person 클래스로 합쳐진 것처럼 동작한다.

public class Person
{
    public string Name { get; set; }
    public void SayHello() { ... }

    public string Address { get; set; }
    public void PrintAddress() { ... }
}

개발자는 파일을 나눠서 관리하지만, 프로그램이 실행될 때는 그냥 한 클래스라고 생각하면 된다.


2. 왜 partial class를 쓰나?

“그냥 한 파일에 다 쓰면 되지, 왜 쪼개서 쓰지?” 라는 생각이 들 수 있다. 대표적인 이유는 세 가지 정도다.

2-1. 자동 생성 코드와 내가 짠 코드를 분리하려고

실무에서 가장 많이 쓰이는 이유는 바로 이거다.

  • WinForms, WPF, ASP.NET WebForms 같은 UI 디자이너를 쓰면
  • 버튼, 텍스트박스 같은 컨트롤을 배치하는 순간 디자이너가 자동으로 코드를 만들어 준다.

예를 들어 WinForms에서 폼 하나를 만들면 이런 구조를 많이 보게 된다.

Form1.cs (내가 작성하는 코드)

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent(); // 디자이너가 만든 설정 코드 호출
    }

    private void button1_Click(object sender, EventArgs e)
    {
        MessageBox.Show("클릭!");
    }
}

Form1.Designer.cs (디자이너가 자동 생성하는 코드)

partial class Form1
{
    private System.Windows.Forms.Button button1;

    private void InitializeComponent()
    {
        this.button1 = new System.Windows.Forms.Button();
        // 위치, 크기, 텍스트, 이벤트 핸들러 연결 등 자동 생성 코드
    }
}

두 파일 모두 partial class Form1로 선언되어 있기 때문에, 둘이 합쳐져서 하나의 Form1 클래스가 된다.

이렇게 나누면 좋은 점:

  • 디자이너가 건드리는 코드내가 직접 쓰는 코드를 파일 수준에서 분리할 수 있다.
  • 디자이너가 .Designer.cs 파일을 자동으로 고쳐도, 내 코드가 섞이지 않는다.
  • 내가 실수로 디자이너 코드 부분을 지워서 폼이 깨지는 일을 줄일 수 있다.

2-2. 클래스가 너무 커서 논리적으로 쪼개고 싶을 때

어떤 클래스가 기능이 많아지면 줄 수가 엄청나게 길어질 수 있다. 예를 들어 OrderService

  • 주문 조회
  • 주문 생성
  • 주문 취소
  • 정산 처리
  • 로그 기록

등이 한꺼번에 들어 있으면 유지보수가 힘들다.

이럴 때 partial로 파일을 역할별로 나눌 수 있다.

OrderService.Query.cs

public partial class OrderService
{
    public Order GetOrder(int id) { ... }

    public List<Order> GetOrdersByCustomer(string customerCode) { ... }
}

OrderService.Command.cs

public partial class OrderService
{
    public void CreateOrder(Order order) { ... }

    public void CancelOrder(int id) { ... }
}

이런 식으로 나누면:

  • “조회 관련 코드만 보고 싶다” → .Query.cs만 열면 됨
  • “등록/수정 관련 코드만 보고 싶다” → .Command.cs만 보면 됨
  • 파일이 나뉘어 있어서 검색/관리/리뷰할 때 훨씬 편하다.

2-3. 여러 사람이 한 클래스를 동시에 작업할 때

팀 작업을 할 때, 한 클래스에 기능이 몰려 있으면 한 파일에서 충돌이 많이 날 수 있다.

  • A 개발자: 조회 기능 작업
  • B 개발자: 등록/수정 기능 작업

이런 상황에서 파일을 나눠 두면, 서로 다른 파일에서 작업할 수 있어서 충돌을 줄일 수 있다.


3. partial class의 규칙과 주의사항

3-1. 이름이 같아야 한다

public partial class Person { ... }
public partial class Person { ... }  // OK, 같은 클래스의 다른 부분

public partial class PersonEx { ... } // 이름이 다르면 완전히 다른 클래스

3-2. 같은 namespace 안에 있어야 한다

// 파일 1
namespace MyApp.Models
{
    public partial class Person { ... }
}

// 파일 2
namespace MyApp.Models   // 네임스페이스가 같아야 합쳐진다
{
    public partial class Person { ... }
}

3-3. 접근 제한자(public, internal 등)는 일관되게

보통 한 파일에만 public partial class를 적고, 나머지는 partial class만 적어도 컴파일은 잘 된다.
하지만 가독성 측면에서는 가능하면 같은 접근제한자로 맞춰주는 편이 좋다.

3-4. 실행될 때는 그냥 “한 클래스”일 뿐

중요한 포인트는, partial은 어디까지나 “코드 작성 편의를 위한 문법”이라는 점이다.

  • 런타임(실행 시점)에는 “부분1, 부분2” 같은 개념이 없다.
  • 그냥 하나의 Person 클래스만 존재한다.
  • partial인지 아닌지 구분할 수 있는 정보도 별로 중요하지 않다.

4. 콘솔 프로젝트에서 직접 써 보는 간단 예제

실제로 partial class가 어떻게 동작하는지, 아주 간단한 예제로 확인해 보자.

Person.Basic.cs

public partial class Person
{
    public string Name { get; set; }
    public int Age { get; set; }

    public void PrintBasicInfo()
    {
        Console.WriteLine($"이름: {Name}, 나이: {Age}");
    }
}

Person.Job.cs

public partial class Person
{
    public string JobTitle { get; set; }

    public void PrintJobInfo()
    {
        Console.WriteLine($"직업: {JobTitle}");
    }
}

Program.cs

using System;

class Program
{
    static void Main()
    {
        Person p = new Person();
        p.Name = "홍길동";
        p.Age = 30;
        p.JobTitle = "개발자";

        p.PrintBasicInfo(); // 이름, 나이 출력
        p.PrintJobInfo();   // 직업 출력

        Console.ReadKey();
    }
}

비록 파일은 3개로 나눠져 있지만, 실제로는 그냥 Person이라는 클래스 한 개가 있는 것처럼 자연스럽게 동작한다.


5. 보너스: partial method 간단 맛보기

partial class 안에서는 partial method도 쓸 수 있다. 이건 자동 생성 코드와 후처리 코드를 나눌 때 유용하다.

파일 1

public partial class Person
{
    partial void OnCreated();

    public Person()
    {
        OnCreated(); // 구현이 있으면 호출, 없으면 컴파일 시 제거됨
    }
}

파일 2

public partial class Person
{
    partial void OnCreated()
    {
        Console.WriteLine("Person 객체가 생성되었습니다.");
    }
}

구현을 해 두면 생성자에서 자동으로 호출되고,
구현을 안 하면 컴파일러가 그냥 이 호출 자체를 지워 버린다.

이건 조금 고급 기능에 가까우니까, “partial class 안에 partial method라는 것도 있다” 정도만 알고 넘어가도 충분하다.


6. 정리

  • partial class는 하나의 클래스를 여러 파일로 나누기 위한 문법이다.
  • 컴파일 시에 여러 파일의 partial 정의들을 합쳐서 하나의 클래스가 된다.
  • 주로:
    • 자동 생성 코드와 직접 작성한 코드를 분리할 때
    • 클래스가 너무 커서 기능별로 파일을 나누고 싶을 때
    • 여러 개발자가 한 클래스를 나눠 작업할 때 사용된다.
  • 이름, namespace가 동일해야 같은 클래스의 partial로 합쳐질 수 있다.
  • 실행 시점에는 그냥 일반 클래스와 완전히 똑같이 취급된다.

앞으로 프로젝트에서 Form1.Designer.cs, SomeWindow.g.cs 같은 파일을 보게 되면, “아, 이게 바로 partial class로 나눠진 자동 생성 코드구나” 하고 이해하면 된다.

0개의 댓글