Sdílet prostřednictvím


Rozšíření částečných metod

Poznámka

Tento článek je specifikace funkce. Specifikace slouží jako návrhový dokument pro funkci. Zahrnuje navrhované změny specifikace spolu s informacemi potřebnými při návrhu a vývoji funkce. Tyto články se publikují, dokud nebudou navrhované změny specifikace finalizovány a začleněny do aktuální specifikace ECMA.

Mezi specifikací funkce a dokončenou implementací může docházet k nějakým nesrovnalostem. Tyto rozdíly jsou zachyceny v příslušných poznámkách schůzky návrhu jazyka (LDM) .

Další informace o procesu přijetí specifikací funkcí do jazyka C# najdete v článku o specifikacích .

Shrnutí

Cílem tohoto návrhu je odstranit všechna omezení týkající se podpisů partial metod v jazyce C#. Cílem je rozšířit sadu scénářů, ve kterých tyto metody mohou pracovat se zdrojovými generátory a obecnějším formulářem deklarace pro metody jazyka C#.

Viz také původní specifikace částečných metod (§15.6.9).

Motivace

Jazyk C# má omezenou podporu pro vývojáře, kteří rozdělují metody na deklarace a definice / implementace.

partial class C
{
    // The declaration of C.M
    partial void M(string message);
}

partial class C
{
    // The definition of C.M
    partial void M(string message) => Console.WriteLine(message);
}

Jedním z chování partial metod je, že když definice chybí, jazyk jednoduše vymaže všechna volání partial metody. V podstatě se chová jako volání metody [Conditional], kde byla podmínka vyhodnocena jako false.

partial class D
{
    partial void M(string message);

    void Example()
    {
        M(GetIt()); // Call to M and GetIt erased at compile time
    }

    string GetIt() => "Hello World";
}

Původní motivací této funkce bylo generování zdroje ve formě kódu generovaného návrhářem. Uživatelé neustále upravovali vygenerovaný kód, protože chtěli připojit určitý aspekt vygenerovaného kódu. Nejvýraznější části procesu spuštění modelu Windows Forms po inicializaci komponent.

Úprava vygenerovaného kódu byla náchylná k chybě, protože jakákoli akce, která způsobila, že návrhář znovu vygeneroval kód, způsobí vymazání úprav uživatele. Funkce metody partial usnadnila toto napětí, protože umožnila návrhářům vkládat háčky ve formě metod partial.

Návrháři můžou generovat háky jako partial void OnComponentInit() a vývojáři by pro ně mohli definovat deklarace nebo je nedefinovat. V obou případech by se vygenerovaný kód zkompiloval a vývojáři, kteří se zajímali o proces, by se podle potřeby mohli připojit.

To znamená, že částečné metody mají několik omezení:

  1. Musí mít void návratový typ.
  2. Nelze použít parametry out.
  3. Nelze mít žádnou přístupnost (implicitně private).

Tato omezení existují, protože jazyk musí být schopen generovat kód při odstranění místa volání. Vzhledem k tomu, že mohou být vymazány, je private jedinou možnou úrovní přístupnosti, protože člen nemůže být zobrazený v metadatech sestavení. Tato omezení také slouží k omezení sady scénářů, ve kterých lze použít partial metody.

Návrhem je odstranit všechna stávající omezení týkající se partial metod. V podstatě jim umožněte mít out parametry, nezáporné návratové typy nebo jakýkoli typ přístupnosti. Takové partial deklarace by pak měly mít přidaný požadavek, že musí existovat definice. To znamená, že jazyk nemusí brát v úvahu dopad mazání volacích míst.

To by rozšířilo sadu scénářů pro generátory, kterých by se metody partial mohly účastnit, a tím by se pěkně propojily s naší funkcí generátorů zdrojového kódu. Například regulární výraz lze definovat pomocí následujícího vzoru:

[RegexGenerated("(dog|cat|fish)")]
partial bool IsPetMatch(string input);

Vývojář tak má jednoduchý deklarativní způsob, jak se přihlásit k generátorům, a také poskytnout generátorům velmi snadnou sadu deklarací, které se dají prohlédnout ve zdrojovém kódu a řídit jejich vygenerovaný výstup.

Porovnejte to s obtížemi, které by měl generátor při integraci následujícího úryvku kódu.

var regex = new RegularExpression("(dog|cat|fish)");
if (regex.IsMatch(someInput))
{

}

Vzhledem k tomu, že kompilátor neumožňuje generátorům upravovat kód připojující se k tomuto vzoru, by pro generátory bylo docela nemožné. Museli by se uchýlit k reflexi v implementaci IsMatch nebo požádat uživatele, aby změnili svá místa volání na novou metodu a upravili regulární výraz tak, aby předával řetězcový literál jako argument. Je to docela nepořádné.

Podrobný návrh

Jazyk se změní tak, aby metody partial byly označeny explicitním přístupovým modifikátorem. To znamená, že mohou být označeny jako private, publicatd ...

Pokud má metoda partial explicitní modifikátor přístupnosti, bude jazyk vyžadovat, aby deklarace má odpovídající definici, i když je přístupnost private:

partial class C
{
    // Okay because no definition is required here
    partial void M1();

    // Okay because M2 has a definition
    private partial void M2();

    // Error: partial method M3 must have a definition
    private partial void M3();
}

partial class C
{
    private partial void M2() { }
}

Dále jazyk odebere všechna omezení toho, co se může zobrazit v metodě partial, která má explicitní přístupnost. Tyto deklarace mohou obsahovat neprázdné návratové typy, out parametry, extern modifikátor atd... Tyto signatury budou mít plnou vyjadřovací schopnost jazyka C#.

partial class D
{
    // Okay
    internal partial bool TryParse(string s, out int i); 
}

partial class D
{
    internal partial bool TryParse(string s, out int i) { ... }
}

To explicitně umožňuje, aby se partial metody účastnily implementace overrides a interface:

interface IStudent
{
    string GetName();
}

partial class C : IStudent
{
    public virtual partial string GetName(); 
}

partial class C
{
    public virtual partial string GetName() => "Jarde";
}

Kompilátor změní chybu, která se vygeneruje, když partial metoda obsahuje neplatný prvek, který v podstatě říká:

Nelze použít ref u metody partial, která nemá explicitní přístupnost

To vývojářům pomůže nasměrovat se správným směrem při používání této funkce.

Omezení:

  • partial deklarace s explicitní přístupností musí mít definici.
  • partial deklarace a podpisy definic se musí shodovat se všemi modifikátory metod a parametrů. Jedinými aspekty, které se mohou lišit, jsou názvy parametrů a seznamy atributů (nejedná se o nový, ale spíše stávající požadavek partial metod).

Otázky

částečné pro všechny členy

Vzhledem k tomu, že rozšiřujeme partial, aby byl přívětivější pro generátory zdrojového kódu, měli bychom ho také rozšířit tak, aby fungoval na všech členech třídy? Měli bychom být například schopni deklarovat partial konstruktory, operátory atd.

řešení Nápad je dobrý, ale v této fázi plánu C# 9 se snažíme vyhnout se zbytečnému přidávání funkcí. Chcete vyřešit okamžitý problém rozšíření funkce pro práci s moderními generátory zdrojů.

Zvažuje se rozšíření partial na podporu dalších členů pro vydání C# 10. Zdá se, že toto rozšíření budeme považovat za pravděpodobné. Toto je aktivní návrh, ale dosud nebyl implementován.

Použijte abstrakci místo částečné

Podstatou tohoto návrhu je v podstatě zajištění, že deklarace má odpovídající definici nebo implementaci. Zda bychom měli použít abstract, protože už je to klíčové slovo jazyka, které nutí vývojáře přemýšlet o implementaci?

Rozhodnutí Proběhla zdravá diskuse, ale nakonec se rozhodlo proti. Ano, požadavky jsou známé, ale koncepty se výrazně liší. Vývojáři by mohli snadno uvěřit, že vytvářejí virtuální sloty, aniž by to skutečně dělali.