Udostępnij za pośrednictwem


Częściowy element członkowski (odwołanie w C#)

Częściowy element członkowski ma jedną deklarację deklarowaną i często jedną deklarację implementjącą. Deklaracja deklaratywna nie zawiera treści. Deklaracja implementowania zawiera treść elementu członkowskiego. Częściowe elementy członkowskie umożliwiają projektantom klas udostępnianie punktów zaczepienia składowych, które można zaimplementować za pomocą narzędzi, takich jak generatory źródeł. Częściowe typy i elementy członkowskie umożliwiają deweloperom ludzkim pisanie części typu, podczas gdy narzędzia piszą inne części typu. Jeśli deweloper nie podasz opcjonalnej deklaracji implementowania, kompilator może usunąć deklarację deklaratora w czasie kompilacji. Następujące warunki dotyczą częściowych elementów członkowskich:

  • Deklaracje muszą zaczynać się od częściowego słowa kluczowego kontekstowego.
  • Podpisy w obu częściach typu częściowego muszą być zgodne.

Słowo partial kluczowe nie jest dozwolone w konstruktorach, finalizatorach, przeciążonych operatorach ani deklaracjach zdarzeń. Przed użyciem języka C# 13 partial nie było dozwolone we właściwościach ani indeksatorach.

Metoda częściowa nie jest wymagana do posiadania deklaracji implementowania w następujących przypadkach:

  • Nie ma żadnych modyfikatorów ułatwień dostępu (w tym domyślnego private).
  • Zwraca wartość void.
  • Nie ma żadnych out parametrów.
  • Nie ma żadnego z następujących modyfikatorów virtual, , overridesealed, newlub extern.

Każdy element członkowski, który nie jest zgodny ze wszystkimi tymi ograniczeniami (na przykład public virtual partial void metodą), musi zapewnić implementację. Właściwości częściowe i indeksatory muszą mieć implementację.

W poniższym przykładzie przedstawiono metodę częściową zgodną z poprzednimi ograniczeniami:

partial class MyPartialClass
{
    // Declaring definition
    partial void OnSomethingHappened(string s);
}

// This part can be in a separate file.
partial class MyPartialClass
{
    // Comment out this method and the program
    // will still compile.
    partial void OnSomethingHappened(string s) =>
        Console.WriteLine($"Something happened: {s}");
}

Częściowe elementy członkowskie mogą być również przydatne w połączeniu z generatorami źródłowymi. Na przykład wyrażenie regularne można zdefiniować przy użyciu następującego wzorca:

public partial class RegExSourceGenerator
{
    [GeneratedRegex("cat|dog", RegexOptions.IgnoreCase, "en-US")]
    private static partial Regex CatOrDogGeneratedRegex();

    private static void EvaluateText(string text)
    {
        if (CatOrDogGeneratedRegex().IsMatch(text))
        {
            // Take action with matching text
        }
    }
}

W poprzednim przykładzie pokazano metodę częściową, która musi mieć deklarację implementającą. W ramach kompilacji generator źródła wyrażeń regularnych tworzy deklarację implementowania.

W poniższym przykładzie pokazano deklarację deklaratywną i deklarację implementjącą dla klasy. Ponieważ zwracany typ metody nie void jest (jest string) i jego dostęp to public, metoda musi mieć deklarację implementowania:

// Declaring declaration
public partial class PartialExamples
{
    /// <summary>
    /// Gets or sets the number of elements that the List can contain.
    /// </summary>
    public partial int Capacity { get; set; }

    /// <summary>
    /// Gets or sets the element at the specified index.
    /// </summary>
    /// <param name="index">The index</param>
    /// <returns>The string stored at that index</returns>
    public partial string this[int index] { get; set; }

    public partial string? TryGetAt(int index);
}

public partial class PartialExamples
{
    private List<string> _items = [
        "one",
        "two",
        "three",
        "four",
        "five"
        ];

    // Implementing declaration

    /// <summary>
    /// Gets or sets the number of elements that the List can contain.
    /// </summary>
    /// <remarks>
    /// If the value is less than the current capacity, the list will shrink to the
    /// new value. If the value is negative, the list isn't modified.
    /// </remarks>
    public partial int Capacity
    {
        get => _items.Count;
        set
        {
            if ((value != _items.Count) && (value >= 0))
            {
                _items.Capacity = value;
            }
        }
    }

    public partial string this[int index]
    {
        get => _items[index];
        set => _items[index] = value;
    }

    /// <summary>
    /// Gets the element at the specified index.
    /// </summary>
    /// <param name="index">The index</param>
    /// <returns>The string stored at that index, or null if out of bounds</returns>
    public partial string? TryGetAt(int index)
    {
        if (index < _items.Count)
        {
            return _items[index];
        }
        return null;
    }
}

W poprzednim przykładzie przedstawiono reguły łączenia dwóch deklaracji:

  • Dopasowania podpisu: Ogólnie rzecz biorąc podpisy deklaracji deklarowanych i implementujących muszą być zgodne. Obejmuje to modyfikator ułatwień dostępu dla metod, właściwości, indeksatorów i poszczególnych metod dostępu. Zawiera on typ parametru i modyfikatory typu ref we wszystkich parametrach. Typ zwracany i dowolny modyfikator typu ref musi być zgodny. Nazwy składowych krotek muszą być zgodne. Jednak niektóre reguły są elastyczne:
    • Deklarowanie i implementowanie deklaracji może mieć różne ustawienia adnotacji dopuszczających wartość null. Oznacza to, że może mieć wartość null bez znaczenia , a druga włączona wartość null.
    • Różnice dotyczące wartości null, które nie obejmują nieświadomości wartości null, powoduje wygenerowanie ostrzeżenia.
    • Domyślne wartości parametrów nie muszą być zgodne. Kompilator wyświetla ostrzeżenie, jeśli implementowanie deklaracji metody lub indeksatora deklaruje domyślną wartość parametru.
    • Kompilator wyświetla ostrzeżenie, gdy nazwy parametrów nie są zgodne. Emitowany il zawiera deklarowane nazwy parametrów deklaracji.
  • Komentarze do dokumentacji: komentarze do dokumentacji mogą być dołączane z obu deklaracji. Jeśli zarówno deklarowanie, jak i implementowanie deklaracji zawiera komentarze do dokumentacji, dołączane są komentarze z deklaracji wykonawczej. W poprzednim przykładzie komentarze do dokumentacji obejmują:
    • Capacity W przypadku właściwości komentarze są pobierane z deklaracji implementowania. Komentarze deklaracji implementowania są używane, gdy obie deklaracje mają /// komentarze.
    • W przypadku indeksatora komentarze są pobierane z deklaracji deklarowanej. Deklaracja implementowania nie zawiera żadnych /// komentarzy.
    • W przypadku TryGetAtelementu komentarze są pobierane z deklaracji implementowania. Deklaracja deklaratywna nie zawiera żadnych /// komentarzy.
    • Wygenerowany kod XML zawiera komentarze do dokumentacji dla wszystkich public członków.
  • Większość deklaracji atrybutów jest łączona. Jednak wszystkie atrybuty informacji o obiekcie wywołującym są definiowane za pomocą polecenia AllowMultiple=false. Kompilator rozpoznaje dowolny atrybut informacji o obiekcie wywołującym w deklaracji deklarowanej. Wszystkie atrybuty informacji o obiekcie wywołującym w deklaracji implementowania są ignorowane. Kompilator wyświetla ostrzeżenie, jeśli dodasz atrybuty informacji o obiekcie wywołującym w deklaracji implementowania.

Zobacz też