Partager via


Membre partiel (Référence C#)

Un membre partiel a une déclaration de déclaration et souvent une déclaration d’implémentation. La déclaration de déclaration ne comprend pas de corps. La déclaration d’implémentation fournit le corps du membre. Les membres partiels permettent aux concepteurs de classes de fournir des points d’ancrage pour les membres, similaires aux gestionnaires d’événements, que les développeurs peuvent choisir de mettre en œuvre ou non. Les types et membres partiels offrent une méthode permettant aux développeurs humains d’écrire une partie d’un type tandis que des outils écrivent d’autres parties du type. Si le développeur ne fournit pas de déclaration d’implémentation facultative, le compilateur peut supprimer la déclaration de déclaration lors de la compilation. Les conditions suivantes s’appliquent aux membres partiels :

  • Les déclarations doivent commencer par le mot clé contextuel partial.
  • Les signatures des deux parties du type partiel doivent correspondre.

Le mot-clé partial n’est pas autorisé sur les constructeurs, les finaliseurs, les opérateurs surchargés ou les déclarations d’événements. Avant C# 13, partial n’était pas autorisé sur les propriétés ou les indexeurs.

Un méthode partielle n’est pas tenue d’avoir une déclaration d’implémentation dans les cas suivants :

  • Elle n’a pas de modificateurs d’accessibilité (y compris le private par défaut).
  • Elle retourne void.
  • Elle n’a pas de paramètres out.
  • Elle n’a aucun des modificateurs suivants virtual, override, sealed, new ou extern.

Tout membre qui ne respecte pas toutes ces restrictions (par exemple, méthode public virtual partial void), doit fournir une implémentation. Les propriétés et indexeurs partiels doivent avoir une implémentation.

L’exemple suivant montre une méthode partielle qui respecte les restrictions précédentes :

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}");
}

Les membres partiels peuvent également être utiles en combinaison avec des générateurs de code source. Par exemple, une expression régulière peut être définie à l’aide du modèle suivant :

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

L’exemple précédent montre une méthode partielle qui doit avoir une déclaration d’implémentation. Dans le cadre d’une build, le générateur de code source d’expressions régulières crée la déclaration d’implémentation.

L’exemple suivant montre une déclaration de déclaration et une déclaration d’implémentation pour une classe. Étant donné que le type de retour de la méthode n’est pas void (c’est string) et que son accès est public, la méthode doit avoir une déclaration d’implémentation :

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

L’exemple précédent illustre les règles sur la façon dont les deux déclarations sont combinées :

  • Correspondance de la signature : En général, les signatures des déclarations de déclaration et d’implémentation doivent correspondre. Cela inclut le modificateur d’accessibilité sur les méthodes, propriétés, indexeurs et accesseurs individuels. Cela inclut le type de paramètre et les modificateurs de type de référence sur tous les paramètres. Le type de retour et tout modificateur de type de référence doivent correspondre. Les noms des membres de tuples doivent correspondre. Cependant, certaines règles sont flexibles :
    • Les déclarations de déclaration et d’implémentation peuvent avoir des paramètres d’annotations nullable différents. Cela signifie que l’une peut être nullable oblivious et l’autre nullable enabled.
    • Les différences de nullabilité qui n’impliquent pas nullable oblivious génèrent un avertissement.
    • Les valeurs par défaut des paramètres n’ont pas besoin de correspondre. Le compilateur émet un avertissement si la déclaration d’implémentation d’une méthode ou d’un indexeur déclare une valeur de paramètre par défaut.
    • Le compilateur émet un avertissement lorsque les noms des paramètres ne correspondent pas. Le code IL émis contient les noms des paramètres de la déclaration de déclaration.
  • Commentaires de documentation : Les commentaires de documentation peuvent être inclus à partir de l’une ou l’autre déclaration. Si les déclarations de déclaration et d’implémentation incluent toutes deux des commentaires de documentation, les commentaires de la déclaration d’implémentation sont inclus. Dans l’exemple précédent, les commentaires de documentation incluent :
    • Pour la propriété Capacity, les commentaires sont tirés de la déclaration d’implémentation. Les commentaires de la déclaration d’implémentation sont utilisés lorsque les deux déclarations comportent des commentaires ///.
    • Pour l’indexeur, les commentaires sont tirés de la déclaration de déclaration. La déclaration d’implémentation n’inclut aucun commentaire ///.
    • Pour TryGetAt, les commentaires sont tirés de la déclaration d’implémentation. La déclaration de déclaration n’inclut aucun commentaire ///.
    • Le XML généré contient des commentaires de documentation pour tous les membres public.
  • La plupart des déclarations d’attributs sont combinées. Cependant, toutes les attributs d’informations sur l’appelant sont définies avec AllowMultiple=false. Le compilateur reconnaît tout attribut d’informations sur l’appelant sur la déclaration de déclaration. Tous les attributs d’informations sur l’appelant sur la déclaration d’implémentation sont ignorés. Le compilateur émet un avertissement si vous ajoutez des attributs d’informations sur l’appelant sur la déclaration d’implémentation.

Voir aussi