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 Type) 정의를 partial로 수정해야 합니다. 예를 들어 다음 클래스 선언은 오류를 생성합니다.
    public partial class A { }
    //public class A { }  // Error, must also be marked partial
    
  • partial 한정자는 키워드(keyword) classstructinterface바로 앞에 나타날 수 있습니다.
  • 다음 예제와 같이 부분 형식(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 메서드를 포함할 수 있습니다. 클래스의 한 부분에는 메서드의 시그니처가 포함되어 있습니다. 구현은 동일한 부분 또는 다른 부분에서 정의될 수 있습니다.

서명이 다음 규칙을 준수하는 경우 부분 메서드에 구현이 필요하지 않습니다.

  • 선언에는 액세스 한정자가 포함되지 않습니다. 메서드는 private 기본적으로 액세스 권한이 있습니다.
  • 반환 형식은 .입니다 void.
  • 매개 변수에는 한정자가 out 없습니다.
  • 메서드 선언에는 다음 한정자를 포함할 수 없습니다.

메서드와 메서드에 대한 모든 호출은 구현이 없을 때 컴파일 시간에 제거됩니다.

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

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

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

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

C# 언어 사양

자세한 내용은 C# 언어 사양의 Partial 형식 및 Partial 메서드참조하세요. 언어 사양은 C# 구문 및 사용법에 대 한 신뢰할 수 있는 소스 됩니다. 부분 메서드에 대한 추가 기능은 기능 사양정의되어 있습니다.

참고 항목