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 częściowego modyfikatora słowa kluczowego, jak pokazano poniżej:

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

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

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
  • 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 typu częściowego są opcjonalne, ale jeśli istnieją w jednej definicji typu częściowego, nie mogą powodować konfliktu ze słowami kluczowymi określonymi 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 klasy Coords, są deklarowane w jednej definicji klasy częściowej, a składowa PrintCoords, jest zadeklarowana w innej definicji klasy częściowej.

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

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() { }
}

Metody częściowe

Klasa częściowa lub struktura może zawierać metodę częściową. Jedna część klasy zawiera podpis metody . 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 (na przykład public virtual partial void metodą), musi zapewnić implementację. Ta implementacja może być dostarczana przez generator źródła.

Metody częściowe umożliwiają implementatorowi jednej części klasy deklarowanie metody. Implementator innej części klasy może zdefiniować tę metodę. 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ę metod. Deweloper ludzki może dodać deklarację metody (często z atrybutami odczytanymi przez generator źródła). Deweloper może napisać kod, który wywołuje te metody. Generator źródła jest uruchamiany podczas kompilacji i zapewnia implementację. W tym scenariuszu ograniczenia dotyczące metod częściowych, 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 metody muszą zaczynać się od częściowego słowa kluczowego kontekstowego.
  • Podpisy metody częściowej w obu częściach typu częściowego muszą być zgodne.
  • Metody częściowe mogą mieć statyczne i niebezpieczne modyfikatory.
  • Metody częściowe mogą być ogólne. 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#. Dodatkowe funkcje metod częściowych są definiowane w specyfikacji funkcji.

Zobacz też