Udostępnij za pośrednictwem


Klasy częściowe i metody (Przewodnik programowania w języku C#)

Istnieje możliwość podzielenia definicji klasy, struktury, interfejsu lub metody na dwa lub więcej plików źródłowych. Każdy plik źródłowy zawiera sekcję definicji typu lub metody, a wszystkie części są łączone podczas kompilowania aplikacji.

Klasy częściowe

Istnieje kilka sytuacji, gdy dzielenie definicji klasy jest pożądane:

  • Deklarowanie klasy na osobnych plikach umożliwia wielu programistom pracę nad nią w tym samym czasie.
  • Możesz dodać kod do klasy bez konieczności ponownego tworzenia pliku źródłowego zawierającego automatycznie wygenerowane źródło. Program Visual Studio używa tego podejścia podczas tworzenia formularzy systemu Windows, kodu otoki usługi sieci Web itd. Możesz utworzyć kod korzystający z tych klas bez konieczności modyfikowania pliku utworzonego przez program Visual Studio.
  • Generatory źródeł mogą generować dodatkowe funkcje w klasie.

Aby podzielić definicję klasy, użyj modyfikatora częściowego słowa kluczowego. W praktyce każda klasa częściowa jest zwykle definiowana w osobnym pliku, co ułatwia zarządzanie i rozszerzanie klasy w czasie.

W poniższym Employee przykładzie pokazano, jak klasa może być podzielona na dwa pliki: Employee_Part1.cs i 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.

Słowo partial kluczowe wskazuje, że w przestrzeni nazw można zdefiniować inne części klasy, struktury lub interfejsu. Wszystkie części muszą używać słowa kluczowego partial . Wszystkie części muszą być dostępne w czasie kompilacji, aby utworzyć ostateczny typ. Wszystkie części muszą mieć takie same ułatwienia dostępu, jak public, privatei tak dalej.

Jeśli jakakolwiek część jest zadeklarowana jako abstrakcyjna, cały typ jest traktowany jako abstrakcyjny. Jeśli jakakolwiek część jest zadeklarowana jako zapieczętowana, cały typ jest uznawany za zamknięty. Jeśli jakakolwiek część deklaruje typ podstawowy, cały typ dziedziczy ten klasę.

Wszystkie części, które określają klasę bazową, muszą się zgadzać, ale części, które pomijają klasę bazową, nadal dziedziczą typ podstawowy. Części mogą określać różne interfejsy podstawowe, a ostateczny typ implementuje wszystkie interfejsy wymienione przez wszystkie deklaracje częściowe. Wszystkie elementy członkowskie klasy, struktury lub interfejsu zadeklarowane w definicji częściowej są dostępne dla wszystkich pozostałych części. Ostatnim typem jest kombinacja wszystkich części w czasie kompilacji.

Uwaga

Modyfikator partial nie jest dostępny w deklaracjach delegata lub wyliczenia.

W poniższym przykładzie pokazano, że zagnieżdżone typy mogą być częściowe, nawet jeśli typ, w ramach którego są zagnieżdżone, nie jest częściowy.

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

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

W czasie kompilacji atrybuty definicji typu częściowego są scalane. Rozważmy na przykład następujące deklaracje:

[SerializableAttribute]
partial class Moon { }

[ObsoleteAttribute]
partial class Moon { }

Są one równoważne następującym deklaracjom:

[SerializableAttribute]
[ObsoleteAttribute]
class Moon { }

Poniżej przedstawiono scalanie ze wszystkich definicji typu częściowego:

  • Komentarze XML. Jeśli jednak oba deklaracje częściowego elementu członkowskiego zawierają komentarze, uwzględniane są tylko komentarze z elementu członkowskiego implementowania.
  • interfejsy
  • atrybuty parametrów typu ogólnego
  • class — Atrybuty
  • członkowie

Rozważmy na przykład następujące deklaracje:

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

Są one równoważne następującym deklaracjom:

class Earth : Planet, IRotate, IRevolve { }

Ograniczenia

Podczas pracy z definicjami klas częściowych należy przestrzegać kilku reguł:

  • Wszystkie definicje typu częściowego przeznaczone do bycia częściami tego samego typu muszą być modyfikowane za pomocą partialpolecenia . Na przykład następujące deklaracje klas generują błąd:
    public partial class A { }
    //public class A { }  // Error, must also be marked partial
    
  • Modyfikator partial może pojawić się bezpośrednio przed słowem kluczowym class, structlub interface.
  • Zagnieżdżone typy częściowe są dozwolone w definicjach typu częściowego, jak pokazano w poniższym przykładzie:
    partial class ClassWithNestedClass
    {
        partial class NestedClass { }
    }
    
    partial class ClassWithNestedClass
    {
        partial class NestedClass { }
    }
    
  • Wszystkie definicje typu częściowego przeznaczone do tego samego typu muszą być zdefiniowane w tym samym zestawie i w tym samym module (.exe lub .dll pliku). Definicje częściowe nie mogą obejmować wielu modułów.
  • Nazwa klasy i parametry typu ogólnego muszą być zgodne ze wszystkimi definicjami typu częściowego. Typy ogólne mogą być częściowe. Każda deklaracja częściowa musi używać tych samych nazw parametrów w tej samej kolejności.
  • Następujące słowa kluczowe w definicji częściowego typu są opcjonalne, ale jeśli istnieją w jednej definicji typu częściowego, to samo należy określić w innej częściowej definicji dla tego samego typu:

Aby uzyskać więcej informacji, zobacz Ograniczenia dotyczące parametrów typu.

Przykłady

W poniższym przykładzie pola i konstruktor Coords klasy są deklarowane w jednej definicji klasy częściowej (Coords_Part1.cs), a PrintCoords metoda jest zadeklarowana w innej definicji klasy częściowej (Coords_Part2.cs). Ta separacja pokazuje, jak klasy częściowe można podzielić na wiele plików, aby ułatwić konserwację.

 // 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

W poniższym przykładzie pokazano, że można również opracowywać częściowe struktury i interfejsy.

partial interface ITest
{
    void Interface_Test();
}

partial interface ITest
{
    void Interface_Test2();
}

partial struct S1
{
    void Struct_Test() { }
}

partial struct S1
{
    void Struct_Test2() { }
}

Częściowe elementy członkowskie

Klasa częściowa lub struktura może zawierać częściową składową. Jedna część klasy zawiera podpis elementu członkowskiego. Implementację można zdefiniować w tej samej części lub w innej części.

Implementacja nie jest wymagana w przypadku metody częściowej, gdy podpis przestrzega następujących reguł:

  • Deklaracja nie zawiera żadnych modyfikatorów dostępu. Metoda ma private domyślnie dostęp.
  • Zwracany typ to void.
  • Żaden z parametrów nie ma out modyfikatora.
  • Deklaracja metody nie może zawierać żadnego z następujących modyfikatorów:

Metoda i wszystkie wywołania metody są usuwane w czasie kompilacji, gdy nie ma implementacji.

Każda metoda, która nie jest zgodna ze wszystkimi tymi ograniczeniami, w tym właściwościami i indeksatorami, musi zapewnić implementację. Ta implementacja może być dostarczana przez generator źródła. Nie można zaimplementować właściwości częściowych przy użyciu automatycznie zaimplementowanych właściwości. Kompilator nie może odróżnić właściwości implementowanej automatycznie i deklaracji deklarowanej właściwości częściowej.

Począwszy od języka C# 13, deklaracja implementowania właściwości częściowej może używać właściwości z kopiami zapasowymi pól do zdefiniowania deklaracji implementowania. Właściwość poparta polem zawiera zwięzłą składnię, w której field słowo kluczowe uzyskuje dostęp do syntetyzowanego pola kopii zapasowej kompilatora dla właściwości. Można na przykład napisać następujące elementy:

// 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; }
}

Można użyć field w metodzie get lub metody set dostępu albo obu tych metod.

Ważne

Słowo field kluczowe jest funkcją w wersji zapoznawczej w języku C# 13. Musisz użyć platformy .NET 9 i ustawić element <LangVersion> na preview w pliku projektu, aby użyć field kontekstu słowa kluczowego.

Należy zachować ostrożność przy użyciu funkcji słowa kluczowego field w klasie, która ma pole o nazwie field. Nowe field słowo kluczowe cieniuje pole o nazwie field w zakresie metody dostępu właściwości. Możesz zmienić nazwę zmiennej field lub użyć tokenu @ , aby odwołać się do identyfikatora field jako @field. Aby dowiedzieć się więcej, przeczytaj specyfikację funkcji słowa kluczowego field.

Metody częściowe umożliwiają implementatorowi jednej części klasy deklarowanie elementu członkowskiego. Implementator innej części klasy może zdefiniować ten element członkowski. Istnieją dwa scenariusze, w których ta separacja jest przydatna: szablony generujące kod standardowy i generatory źródeł.

  • Kod szablonu: szablon rezerwuje nazwę i podpis metody, aby wygenerowany kod mógł wywołać metodę. Te metody są zgodne z ograniczeniami, które umożliwiają deweloperowi podjęcie decyzji, czy wdrożyć metodę. Jeśli metoda nie jest zaimplementowana, kompilator usuwa sygnaturę metody i wszystkie wywołania metody. Wywołania metody, w tym wszelkie wyniki, które byłyby wykonywane z oceny argumentów w wywołaniach, nie mają wpływu w czasie wykonywania. W związku z tym każdy kod w klasie częściowej może swobodnie używać metody częściowej, nawet jeśli implementacja nie jest podana. Jeśli metoda jest wywoływana, ale nie jest implementowana, nie występują błędy w czasie kompilacji ani w czasie wykonywania.
  • Generatory źródeł: generatory źródeł zapewniają implementację elementów członkowskich. Deweloper ludzki może dodać deklarację elementu członkowskiego (często z atrybutami odczytanymi przez generator źródła). Deweloper może napisać kod wywołujący te elementy członkowskie. Generator źródła jest uruchamiany podczas kompilacji i zapewnia implementację. W tym scenariuszu ograniczenia częściowych elementów członkowskich, które mogą nie być implementowane, często nie są przestrzegane.
// Definition in file1.cs
partial void OnNameChanged();

// Implementation in file2.cs
partial void OnNameChanged()
{
  // method body
}
  • Częściowe deklaracje składowe muszą zaczynać się od częściowego słowa kluczowego kontekstowego.
  • Podpisy częściowe elementów członkowskich w obu częściach typu częściowego muszą być zgodne.
  • Częściowy element członkowski może mieć statyczne i niebezpieczne modyfikatory.
  • Częściowy element członkowski może być ogólny. Ograniczenia muszą być takie same w deklaracji metody definiowania i implementowania. Nazwy parametrów i typów nie muszą być takie same w deklaracji implementowania, jak w definicji.
  • Można utworzyć delegata do metody częściowej zdefiniowanej i zaimplementowanej, ale nie do metody częściowej, która nie ma implementacji.

Specyfikacja języka C#

Aby uzyskać więcej informacji, zobacz Częściowe typy i metody częściowe w specyfikacji języka C#. Specyfikacja języka jest ostatecznym źródłem informacji o składni i użyciu języka C#. Nowe funkcje metod częściowych są definiowane w specyfikacji funkcji.

Zobacz też