다음을 통해 공유


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

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

partial 클래스

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

  • 별도의 파일에 클래스를 선언하면 여러 프로그래머가 동시에 작업할 수 있습니다.
  • 자동으로 생성된 원본을 포함하는 소스 파일을 다시 만들 필요 없이 클래스에 코드를 추가할 수 있습니다. Visual Studio에서는 Windows Forms, 웹 서비스 래퍼 코드 등에 만들 때 이 방식을 사용합니다. Visual Studio에서 만든 파일을 수정하지 않고도 이러한 클래스를 사용하는 코드를 만들 수 있습니다.
  • 원본 생성기는 클래스에서 추가 기능을 생성할 수 있습니다.

클래스 정의를 분할하려면 부분 키워드 한정자를 사용합니다. 실제로 각 부분 클래스는 일반적으로 별도의 파일에 정의되므로 시간이 지남에 따라 클래스를 보다 쉽게 관리하고 확장할 수 있습니다.

다음 예제에서는 Employee 클래스를 Employee_Part1.cs 및 Employee_Part2.cs 두 파일로 나누는 방법을 보여 줍니다.

// This is in Employee_Part1.cs
public partial class Employee
{
    public void DoWork()
    {
        Console.WriteLine("Employee is working.");
    }
}

// This is in Employee_Part2.cs
public partial class Employee
{
    public void GoToLunch()
    {
        Console.WriteLine("Employee is at lunch.");
    }
}

//Main program demonstrating the Employee class usage
public class Program
{
    public static void Main()
    {
        Employee emp = new Employee();
        emp.DoWork();
        emp.GoToLunch();
    }
}

// Expected Output:
// Employee is working.
// Employee is at lunch.

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 주석. 그러나 partial 멤버의 두 선언 모두 주석이 포함된 경우 구현 멤버의 주석만 포함됩니다.
  • 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 한정자는 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) 정의에서 클래스 이름 및 제네릭 형식 매개 변수가 일치해야 합니다. 제네릭 형식은 부분일 수 있습니다. 각 부분 선언에서 동일한 매개 변수 이름을 동일한 순서로 사용해야 합니다.
  • 부분 형식(Partial Type) 정의에서 다음의 키워드는 선택 사항이지만, 부분 형식(Partial Type) 정의에 있는 경우 동일한 형식의 다른 부분 정의에서도 동일하게 지정해야 합니다.

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

예제

다음 예제에서는 클래스의 Coords 필드와 생성자가 한 부분 클래스 정의()Coords_Part1.cs에 선언되고 PrintCoords 메서드는 다른 partial 클래스 정의(Coords_Part2.cs)에서 선언됩니다. 이 분리는 손쉽게 유지 관리하기 위해 부분 클래스를 여러 파일에 분할할 수 있는 방법을 보여 줍니다.

 // This is in Coords_Part1.cs
 public partial class Coords
 {
     private int x;
     private int y;

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

 // This is in Coords_Part2.cs
 public partial class Coords
 {
     public void PrintCoords()
     {
         Console.WriteLine("Coords: {0},{1}", x, y);
     }
 }

// Main program demonstrating the Coords class usage
 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 클래스 또는 구조체에는 partial 멤버가 포함될 수 있습니다. 클래스의 한 부분에는 멤버의 시그니처가 포함되어 있습니다. 구현은 동일한 부분 또는 다른 부분에서 정의될 수 있습니다.

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

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

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

속성 및 인덱서를 포함하여 해당 제한 사항을 모두 따르지 않는 메서드는 구현을 제공해야 합니다. 해당 구현은 원본 생성기에 의해 제공될 수 있습니다. 부분 속성 은 자동으로 구현된 속성을 사용하여 구현할 수 없습니다. 컴파일러는 자동으로 구현된 속성과 partial 속성의 선언 선언을 구분할 수 없습니다.

C# 13부터 partial 속성에 대한 구현 선언은 필드 백업 속성을 사용하여 구현 선언을 정의할 수 있습니다. 지원되는 필드 속성은 키워드가 field 속성에 대한 컴파일러 합성 지원 필드에 액세스하는 간결한 구문을 제공합니다. 예를 들어 다음을 작성할 수 있습니다.

// in file1.cs
public partial class PropertyBag
{
    // Defining declaration
    public partial int MyProperty { get; set; }
}

// In file2.cs
public partial class PropertyBag
{
    // Defining declaration
    public partial int MyProperty { get => field; set; }
}

또는 접근자 get 또는 set 둘 다에서 사용할 field 수 있습니다.

Important

field 키워드는 C# 13의 미리 보기 기능입니다. 상황별 키워드를 사용하려면 .NET 9를 preview 사용하고 field 프로젝트 파일에서 요소를 설정 <LangVersion> 해야 합니다.

이름이 지정된 field필드가 field 있는 클래스에서 키워드 기능을 사용하는 데 주의해야 합니다. 새 field 키워드는 속성 접근자의 범위에 명명된 field 필드를 숨깁니다. 변수의 field 이름을 변경하거나 토큰을 사용하여 @ 식별자를 .로 @field참조 field 할 수 있습니다. 키워드에 대한 field 기능 사양을 읽어 자세히 알아볼 수 있습니다.

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

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

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

C# 언어 사양

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

참고 항목