Partial 클래스 및 메서드(C# 프로그래밍 가이드)

클래스, 구조체, 인터페이스 또는 메서드의 정의를 둘 이상의 소스 파일에 분할할 수 있습니다. 각 소스 파일에는 형식 또는 메서드 정의 섹션이 있으며 모든 부분은 애플리케이션이 컴파일될 때 결합됩니다.

partial 클래스

클래스 정의를 분할하는 것이 바람직한 몇 가지 상황이 있습니다.

  • 대규모 프로젝트에서 작업하는 경우 클래스를 개별 파일에 분산하면 여러 프로그래머가 동시에 클래스에 대해 작업할 수 있습니다.
  • 자동으로 생성된 소스로 작업하는 경우 소스 파일을 다시 만들지 않고도 클래스에 코드를 추가할 수 있습니다. Visual Studio에서는 Windows Forms, 웹 서비스 래퍼 코드 등에 만들 때 이 방식을 사용합니다. Visual Studio에서 만든 파일을 수정하지 않고도 이러한 클래스를 사용하는 코드를 만들 수 있습니다.
  • 소스 생성기를 사용하여 클래스에서 추가 기능을 생성하는 경우

클래스 정의를 분할하려면 다음과 같이 partial 키워드 한정자를 사용합니다.

public partial class Employee
{
    public void DoWork()
    {
    }
}

public partial class Employee
{
    public void GoToLunch()
    {
    }
}

partial 키워드는 클래스, 구조체 또는 인터페이스의 다른 부분을 네임스페이스에서 정의할 수 있음을 나타냅니다. 모든 부분은 partial 키워드를 사용해야 합니다. 최종 형식을 생성하려면 컴파일 시간에 모든 부분을 사용할 수 있어야 합니다. 모든 부분에 public, private 등의 동일한 액세스 가능성이 있어야 합니다.

부분이 abstract로 선언된 경우 전체 형식이 abstract로 간주됩니다. 부분이 sealed로 선언된 경우 전체 형식이 sealed로 간주됩니다. 부분이 기본 형식을 선언하는 경우 전체 형식이 해당 클래스를 상속합니다.

기본 클래스를 지정하는 부분은 모두 일치해야 하지만 기본 클래스를 생략하는 부분도 여전히 기본 형식을 상속합니다. 부분에서 다른 기본 인터페이스를 지정할 수 있으며, 최종 형식은 모든 partial 선언에 나열된 모든 인터페이스를 구현합니다. 부분 정의에 선언된 클래스, 구조체 또는 인터페이스 멤버는 다른 모든 부분에서 사용할 수 있습니다. 최종 형식은 컴파일 시간의 모든 부분 조합입니다.

참고 항목

대리자 또는 열거형 선언에서는 partial 한정자를 사용할 수 없습니다.

다음 예제에서는 중첩된 대상 형식 자체는 부분이 아니어도 중첩된 형식이 부분일 수 있음을 보여 줍니다.

class Container
{
    partial class Nested
    {
        void Test() { }
    }

    partial class Nested
    {
        void Test2() { }
    }
}

컴파일 시간에 부분 형식(Partial Type) 정의의 특성이 병합됩니다. 예를 들어 다음 선언을 살펴보세요.

[SerializableAttribute]
partial class Moon { }

[ObsoleteAttribute]
partial class Moon { }

이러한 선언은 다음 선언과 동일합니다.

[SerializableAttribute]
[ObsoleteAttribute]
class Moon { }

다음은 모든 부분 형식(Partial Type) 정의에서 병합됩니다.

  • XML 주석
  • interfaces
  • 제네릭 형식 매개 변수 특성
  • 클래스 특성
  • 구성원

예를 들어 다음 선언을 살펴보세요.

partial class Earth : Planet, IRotate { }
partial class Earth : IRevolve { }

이러한 선언은 다음 선언과 동일합니다.

class Earth : Planet, IRotate, IRevolve { }

제한 사항

partial 클래스 정의로 작업할 때 따라야 할 몇 가지 규칙이 있습니다.

  • 동일한 형식의 일부로 작성된 모든 부분 형식(Partial Type) 정의를 partial로 수정해야 합니다. 예를 들어 다음 클래스 선언은 오류를 생성합니다.
    public partial class A { }
    //public class A { }  // Error, must also be marked partial
    
  • partial 한정자는 class, struct 또는 interface 키워드 바로 앞에만 올 수 있습니다.
  • 다음 예제와 같이 부분 형식(Partial Type) 정의에 중첩된 부분 형식(Partial Type)을 사용할 수 있습니다.
    partial class ClassWithNestedClass
    {
        partial class NestedClass { }
    }
    
    partial class ClassWithNestedClass
    {
        partial class NestedClass { }
    }
    
  • 동일한 형식의 일부로 작성된 모든 부분 형식(Partial Type) 정의는 동일한 어셈블리와 동일한 모듈(.exe 또는 .dll 파일)에서 정의해야 합니다. 부분 정의는 여러 모듈에 걸쳐 있을 수 없습니다.
  • 모든 부분 형식(Partial Type) 정의에서 클래스 이름 및 제네릭 형식 매개 변수가 일치해야 합니다. 제네릭 형식은 부분일 수 있습니다. 각 부분 선언에서 동일한 매개 변수 이름을 동일한 순서로 사용해야 합니다.
  • 부분 형식 정의에 대한 다음 키워드(keyword) 선택 사항이지만 한 부분 형식 정의에 있는 경우 동일한 형식의 다른 부분 정의에 지정된 키워드(keyword) 충돌할 수 없습니다.

자세한 내용은 형식 매개 변수에 대한 제약 조건을 참조하세요.

예제

다음 예제에서는 Coords 클래스의 생성자 및 필드가 하나의 partial 클래스 정의에서 선언되고 PrintCoords 멤버가 다른 partial 클래스 정의에서 선언됩니다.

public partial class Coords
{
    private int x;
    private int y;

    public Coords(int x, int y)
    {
        this.x = x;
        this.y = y;
    }
}

public partial class Coords
{
    public void PrintCoords()
    {
        Console.WriteLine("Coords: {0},{1}", x, y);
    }
}

class TestCoords
{
    static void Main()
    {
        Coords myCoords = new Coords(10, 15);
        myCoords.PrintCoords();

        // Keep the console window open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}
// Output: Coords: 10,15

다음 예제에서는 partial 구조체와 인터페이스도 개발할 수 있음을 보여 줍니다.

partial interface ITest
{
    void Interface_Test();
}

partial interface ITest
{
    void Interface_Test2();
}

partial struct S1
{
    void Struct_Test() { }
}

partial struct S1
{
    void Struct_Test2() { }
}

부분 메서드

partial 클래스 또는 구조체에는 부분 메서드(Partial Method)가 포함될 수 있습니다. 클래스의 한 부분에는 메서드의 시그니처가 포함되어 있습니다. 구현은 동일한 부분 또는 다른 부분에서 정의될 수 있습니다. 구현을 제공하지 않으면 메서드와 모든 메서드 호출이 컴파일 시간에 제거됩니다. 메서드 시그니처에 따라 구현이 필요할 수 있습니다. 부분 메서드는 다음 경우에 구현을 포함할 필요가 없습니다.

해당 일부 제한 사항을 따르지 않는 모든 메서드(public virtual partial void 메서드)는 구현을 제공해야 합니다. 이 구현은 소스 생성기에서 제공될 수 있습니다.

부분 메서드를 사용하면 클래스의 한 부분의 구현자가 메서드를 선언할 수 있습니다. 클래스의 다른 부분의 구현자는 해당 메서드를 정의할 수 있습니다. 유용하게 사용할 수 있는 두 가지 시나리오는 상용구 코드를 생성하는 템플릿과 소스 생성기입니다.

  • 템플릿 코드: 생성된 코드에서 메서드를 호출할 수 있도록 템플릿에서 메서드 이름 및 시그니처를 예약합니다. 이러한 메서드는 개발자가 메서드를 구현할지 여부를 결정할 수 있도록 지원하는 제한 사항을 따릅니다. 메서드가 구현되지 않은 경우 컴파일러는 메서드 시그니처 및 모든 메서드 호출을 제거합니다. 호출의 인수 평가에서 발생하는 모든 결과를 포함하여 메서드 호출은 런타임에 영향을 주지 않습니다. 따라서 partial 클래스의 코드는 구현이 제공되지 않은 경우에도 부분 메서드(Partial Method)를 자유롭게 사용할 수 있습니다. 메서드가 호출되었지만 구현되지 않은 경우 컴파일 시간 또는 런타임 오류가 발생하지 않습니다.
  • 소스 생성기: 소스 생성기는 메서드에 대한 구현을 제공합니다. 휴먼 개발자는 메서드 선언을 추가할 수 있습니다(소스 생성기에서 읽은 특성이 포함되는 경우가 많음). 개발자는 이러한 메서드를 호출하는 코드를 작성할 수 있습니다. 소스 생성기는 컴파일 중에 실행되고 구현을 제공합니다. 이 시나리오에서는 구현되지 않을 수 있는 부분 메서드에 대한 제한을 따르지 않는 경우가 많습니다.
// Definition in file1.cs
partial void OnNameChanged();

// Implementation in file2.cs
partial void OnNameChanged()
{
  // method body
}
  • 부분 메서드 선언은 상황별 키워드 partial로 시작해야 합니다.
  • 부분 형식(Partial Type)의 두 부분에 있는 부분 메서드 시그니처가 일치해야 합니다.
  • 부분 메서드(Partial Method)는 staticunsafe 한정자를 사용할 수 없습니다.
  • 부분 메서드(Partial Method)는 제네릭일 수 있습니다. 제약 조건은 정의하는 부분 메서드(Partial Method) 선언에 배치되며 필요에 따라 구현하는 선언에서 반복될 수 있습니다. 매개 변수 및 형식 매개 변수 이름이 정의하는 선언과 구현하는 선언에서 동일할 필요는 없습니다.
  • 정의 및 구현된 부분 메서드(Partial Method)에 대한 대리자는 만들 수 있지만 정의만 된 부분 메서드(Partial Method)에 대한 대리자는 만들 수 없습니다.

C# 언어 사양

자세한 내용은 C# 언어 사양부분 형식을 참조하세요. 언어 사양은 C# 구문 및 사용법에 대 한 신뢰할 수 있는 소스 됩니다.

참고 항목