Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Jegyzet
Ez a cikk egy funkcióspecifikáció. A specifikáció a funkció tervezési dokumentumaként szolgál. Tartalmazza a specifikáció javasolt módosításait, valamint a funkció tervezése és fejlesztése során szükséges információkat. Ezeket a cikkeket mindaddig közzéteszik, amíg a javasolt specifikációmódosításokat nem véglegesítik, és be nem építik a jelenlegi ECMA-specifikációba.
A szolgáltatás specifikációja és a befejezett implementáció között eltérések lehetnek. Ezeket a különbségeket a vonatkozó nyelvi tervezési értekezlet (LDM) megjegyzései rögzítik.
A funkcióspektusok C# nyelvi szabványba való bevezetésének folyamatáról a specifikációkcímű cikkben olvashat bővebben.
Bajnoki probléma: https://github.com/dotnet/csharplang/issues/49
Összefoglalás
Támogassa a kovariáns visszatérési típusokat. Engedélyezi egy metódus felülírását olyan módon, hogy a felülbírt metódusnál származtatottabb visszatérési típust deklaráljon, és hasonlóképpen engedélyezi egy írásvédett tulajdonság felülírását, hogy származtatottabb típust deklaráljon. A származtatottabb típusok esetében megjelenő felülbírálási deklarációknak legalább olyan specifikus visszatérési típust kell biztosítaniuk, mint ami az alaptípusok felülbírálásaiban jelenik meg. A metódus vagy tulajdonság hívói statikusan kapják meg a kifinomultabb visszatérési típust egy meghívásból.
Motiváció
A kódban gyakran előfordul, hogy különböző metódusneveket kell feltalálni a nyelvi kényszer megkerüléséhez, amelyet a felülbírálásoknak ugyanazt a típust kell visszaadnia, mint a felülbírált metódusnak.
Ez hasznos lehet a gyári mintában. Például a Roslyn-kódbázisban
class Compilation ...
{
public virtual Compilation WithOptions(Options options)...
}
class CSharpCompilation : Compilation
{
public override CSharpCompilation WithOptions(Options options)...
}
Részletes kialakítás
Ez a C#-ban lévő specifikáció a kovariáns visszatérési típusokkal kapcsolatos. A szándékunk az, hogy egy metódus felülbírálása a felülbírált metódusnál származtatottabb visszatérési típust adjon vissza, és hasonlóképpen lehetővé teszi, hogy egy írásvédett tulajdonság felülbírálása származtatottabb visszatérési típust adjon vissza. A metódus vagy tulajdonság hívói statikusan kapják meg a kifinomultabb visszatérési típust egy meghívásból, és a származtatottabb típusok esetében megjelenő felülbírálásoknak legalább olyan konkrét visszatérési típust kell biztosítaniuk, mint ami az alaptípus felülbírálásaiban jelenik meg.
Osztálymetódus felülbírálása
Az osztály felülbírálásának meglévő korlátozása (§15.6.5) metódusok
- A felülbírálási módszer és a felülbírált alapmetódus ugyanazzal a visszatérési típussal rendelkezik.
módosítva lett
- A felülbírálási metódusnak olyan visszatérési típussal kell rendelkeznie, amely identitáskonvertálással konvertálható, vagy (ha a metódus értékvisszatérítéssel rendelkezik – nem ref visszatérési lásd 13.1.0.5. implicit referenciaátalakítást a felülbírált alapmetódus visszatérési típusára.
És a következő további követelmények hozzá vannak fűzve a listához:
- A felülbírálási metódusnak olyan visszatérési típussal kell rendelkeznie, amely identitási konverzióval átalakítható, vagy ha a metódus értékvisszatérítéssel rendelkezik (és nem egy referencia visszatérítés,, §13.1.0.5) implicit referenciakonverzióval konvertálható a felülbírált alapmetódus minden, a felülbírálási metódus (közvetlen vagy közvetett) alaptípusában deklarált felülbírálásának visszatérési típusára.
- A felülbírálási metódus visszatérési típusának legalább olyan akadálymentesnek kell lennie, mint a felülbírálási módszer (Akadálymentességi tartományok – §7.5.3).
Ez a korlátozás lehetővé teszi, hogy egy private osztály felülbírálási metódusa private visszatérési típussal rendelkezzen. Azonban szükség van egy public felülbírálási metódusra a public típusban, hogy public visszatérési típussal rendelkezzen.
Az osztály tulajdonságának és az indexelőnek a felülbírálása
Az osztályok felülbírálási korlátozásának meglévő tulajdonságai (§15.7.6)
A felülíró tulajdonságdeklarációnak pontosan ugyanazokat az akadálymentességi módosítókat és nevet kell megadnia, mint az örökölt tulajdonság, és identitásátalakítást kell
a felülírás típusa és az örökölt tulajdonságközött. Ha az örökölt jellemzőnek csak egyetlen hozzáférője van (azaz ha az örökölt jellemző csak olvasható vagy csak írható), a felülíró jellemzőnek csak ezt a hozzáférőt kell tartalmaznia. Ha az örökölt tulajdonság mindkét tartozékot tartalmazza (azaz ha az örökölt tulajdonság írás-olvasás), a felülíró tulajdonság egyetlen tartozékot vagy mindkét tartozékot tartalmazhat.
módosítva lett
A felülíró tulajdonságdeklarációnak pontosan ugyanazokat a hozzáférési módosítókat és nevet kell megadnia, mint az öröklött tulajdonság, és identitásátalakításnak kell lennie , vagy (ha az örökölt tulajdonság írásvédett, és értéket ad vissza – nem ref visszatérés§13.1.0.5esetén) implicit referenciaátalakításnak kell lennie a felülíró tulajdonság típusáról az örökölt tulajdonság típusára. Ha az örökölt jellemzőnek csak egyetlen hozzáférője van (azaz ha az örökölt jellemző csak olvasható vagy csak írható), a felülíró jellemzőnek csak ezt a hozzáférőt kell tartalmaznia. Ha az örökölt tulajdonság mindkét tartozékot tartalmazza (azaz ha az örökölt tulajdonság írás-olvasás), a felülíró tulajdonság egyetlen tartozékot vagy mindkét tartozékot tartalmazhat. A felülíró tulajdonság típusának legalább olyan akadálymentesnek kell lennie, mint a felülíró tulajdonság (Akadálymentességi tartományok – 7.5.3.).
Az alábbi specifikációtervezet hátralevő része további bővítést javasol az interfészmódszerek ko-variáns visszatéréseire, amelyeket később megfontolnak.
Interfész metódus, tulajdonság és indexelő felülbírálása
A C# 8.0 dim funkcióval kiegészített felületen engedélyezett tagtípusokhoz hozzáadva a kovriant visszatérésekkel együtt override tagok támogatását is hozzáadjuk. Ezek az osztályokhoz megadott override tagokra vonatkozó szabályokat követik, az alábbi különbségekkel:
Az osztályokban a következő szöveg:
A felülbírálási deklaráció által felülbírált metódus az felülbírált alapmetódus. Egy
Mosztályban deklarált felülbírálásiCmódszernél a felülbírált alapmetódus aCminden alaposztályának vizsgálatával határozható meg, kezdve aCközvetlen alaposztályával, és az egyes egymást követő közvetlen alaposztályokkal folytatva, amíg egy adott alaposztálytípusban legalább egy olyan elérhető metódus található, amelynek aláírása megegyezik a típusargumentumok helyettesítése utánMaláírásával.
az interfészek megfelelő specifikációját adja meg:
A felülbírálási deklaráció által felülbírált metódus az felülbírált alapmetódus. Egy felületen
MIdeklarált felülbírálási módszer esetében a felülbírált alapmetódus aIminden közvetlen vagy közvetett alapfelületének vizsgálatával határozható meg, összegyűjtve azokat az interfészeket, amelyek olyan elérhető módszert deklarálnak, amelynek aláírása aM-mal megegyezik a típusargumentumok helyettesítése után. Ha ez az illesztőkészlet rendelkezik egy legjobban származtatotttípussal, amelyhez a készlet minden típusában van azonosság- vagy implicit referenciaátalakítás, és ez a típus egyedi ilyen metódusdeklarációt tartalmaz, akkor ez a felüldefiniált alapmetódus.
Hasonlóképpen engedélyezzük a override tulajdonságokat és indexelőket az interfészekben, ahogy az az osztályoknál meghatározásra került a §15.7.6 virtuális, lezárt, felülbíráló és absztrakt hozzáférési metódusaira vonatkozóan.
Névkeresés
A névkeresés az osztály override deklarációk jelenlétében jelenleg úgy módosítja a névkeresés eredményét, hogy az azonosító minősítőjének típusától kiindulva, vagy ha nincs minősítő, akkor override-től kezdve az osztályhierarchiában az a leginkább származtatott this deklarációból származó tagrészletek kerüljenek alkalmazásra. Például a §12.6.2.2 Megfelelő paraméterek-ben.
Az osztályokban definiált virtuális metódusok és indexelők esetében a paraméterlista a függvénytag első deklarációjából vagy felülbírálásából lesz kiválasztva, amikor a fogadó statikus típusával kezdődik, és az alaposztályokon keresztül keres.
ehhez hozzáadjuk
Az interfészekben definiált virtuális metódusok és indexelők esetében a paraméterlista a függvénytag deklarációjából vagy a felülbírálás deklarációjából lesz kiválasztva, amely a legszármaztatottabb típusban található az olyan típusok közül, amelyek tartalmazzák a függvénytag felülbírálásának deklarálását. Fordítási időbeli hiba, ha nem létezik ilyen egyedi típus.
A tulajdonság vagy indexelő hozzáférés eredménytípusára vonatkozóan a meglévő szöveg a következő.
- Ha
Iazonosít egy példánytulajdonságot, akkor az eredmény egy tulajdonsághozzáférés aEtársított példánykifejezésével és egy társított típussal, amely a tulajdonság típusa. HaTosztálytípus, akkor a társított típust a tulajdonság első deklarációjából vagy felülbírálásából választják ki, amelyet aT-től kezdődően keresnek az alaposztályokon keresztül.
ki van bővítve
Ha
Tegy interfésztípus, a társított típust a rendszer aTvagy közvetlen vagy közvetett alapfelületeinek leg származtatottabb tulajdonságában található tulajdonság deklarációjából vagy felülbírálásából választja ki. Fordítási időbeli hiba, ha nem létezik ilyen egyedi típus.
Hasonló módosítást kell tenni a 12.8.12.3 szakaszban az indexelő hozzáférésnél
A 12.8.10 meghívási kifejezésekben bővítjük a meglévő szöveget
- Ellenkező esetben az eredmény egy érték, amely a metódus vagy delegált visszatérési típusának egy társított típusával rendelkezik. Ha a meghívás egy példány metódusra történik, és a fogadó osztálytípusú,
T, akkor a társított típust a metódus első deklarációjából vagy felülírásából választják ki, miután a kereséstT-nél elkezdik és végigmennek az alaposztályokon.
val
Ha a meghívás egy példánymetódus, és a fogadó
Tinterfész típusú, akkor a rendszer a társított típust aTés közvetlen és közvetett alapfelületei közül a legszármozottabb interfészben található metódus deklarációjából vagy felülbírálásából választja ki. Fordítási időbeli hiba, ha nem létezik ilyen egyedi típus.
Implicit felület implementációi
A specifikáció ezen szakasza
Az interfész leképezése céljából egy osztálytag
Aakkor felel meg egy interfésztagnakB, ha:
AésBmetódusok, és aAésBneve, típusa és formális paraméterlistái azonosak.AésBtulajdonságok, aAés aBneve és típusa megegyezik, ésAugyanazokkal a tartozékokkal rendelkezik, mintB(Atovábbi tartozékokkal is rendelkezhet, ha nem explicit felülettag-implementáció).AésBesemények, és aAésBneve és típusa azonos.AésBindexelők, aAésBtípus- és formális paraméterlistái azonosak, ésAugyanazokkal a tartozékokkal rendelkezik, mintB(Atovábbi tartozékokkal is rendelkezhet, ha nem explicit felülettag-implementáció).
az alábbiak szerint módosul:
Az interfész leképezése céljából egy osztálytag
Aakkor felel meg egy interfésztagnakB, ha:
AésBmetódusok, és aAésBnév- és formális paraméterlistái azonosak, és aAvisszatérési típusa átalakítható aBvisszatérési típusára az implicit hivatkozás konvertálásának identitásán keresztül aBvisszatérési típusára.AésBtulajdonságok, aAés aBneve azonos,Augyanazokkal a tartozékokkal rendelkezik, mintB(Atovábbi tartozékokkal is rendelkezhet, ha nem explicit felülettag-implementáció), és aAtípusa identitáskonvertálással átalakítható aBvisszatérési típusára, vagy haAolvasható tulajdonság, implicit referenciakonvertálás.AésBesemények, és aAésBneve és típusa azonos.AésBindexelők, aAésBformális paraméterlistái azonosak,Augyanazokkal a tartozékokkal rendelkezik, mintB(Atovábbi tartozékokkal is rendelkezhet, ha nem explicit interfésztag-implementáció), és aAtípusa identitásátalakítással átalakítható aBvisszatérési típusára, vagy haAegy olvasható indexelő, implicit referenciakonvertálás.
Ez technikailag egy kódtörő változás, mivel az alábbi program ma a „C1.M” szöveget írja ki, de a javasolt változtatás esetén a „C2.M” jelenne meg.
using System;
interface I1 { object M(); }
class C1 : I1 { public object M() { return "C1.M"; } }
class C2 : C1, I1 { public new string M() { return "C2.M"; } }
class Program
{
static void Main()
{
I1 i = new C2();
Console.WriteLine(i.M());
}
}
A kompatibilitástörő változás miatt megfontolhatjuk, hogy nem támogatjuk a kovariantikus visszatérési típusokat implicit implementációk esetében.
A felület implementálásának korlátozásai
Olyan szabályra lesz szükségünk, amely szerint az explicit interfész-implementációnak nem lehet alacsonyabb szintű visszatérési típusa, mint a visszatérési típus, amelyet bármelyik alapinterfész felülbírálásában deklarált.
API-kompatibilitási következmények
még meghatározandó
Nyitott kérdések
A specifikáció nem határozza meg, hogy a hívó hogyan kapja meg a pontosabb visszatérési típust. Feltehetően ez a folyamat ahhoz hasonló módon történik, ahogy a hívók megkapják a leginkább származtatott felülbírálás paraméterspecifikációit.
Ha a következő felületekkel rendelkezünk:
interface I1 { I1 M(); }
interface I2 { I2 M(); }
interface I3: I1, I2 { override I3 M(); }
Vegye figyelembe, hogy I3a metódusok I1.M() és I2.M() "egyesítve" lettek. A I3megvalósításakor mindkettőt együtt kell megvalósítani.
Általában explicit implementációra van szükség az eredeti módszerre való hivatkozáshoz. A kérdés az, hogy egy osztályban
class C : I1, I2, I3
{
C IN.M();
}
Mit jelent ez itt? Mi legyen N?
Azt javaslom, hogy engedélyezzük I1.M vagy I2.M (de mindkettőt nem), és ezt mindkettő megvalósításaként kezeljük.
Hátránya
- [ ] Minden nyelvváltoztatásnak meg kell térülnie.
- [] Biztosítanunk kell, hogy a teljesítmény ésszerű legyen, még a mély öröklési hierarchiák esetén is
- [] Biztosítanunk kell, hogy a fordítási stratégia összetevői ne befolyásolják a nyelvi szemantikát, még akkor sem, ha régi fordítóktól származó új IL-t használnak.
Alternatívák
Kicsit lazíthatnánk a nyelvi szabályokon, hogy a forrásban
// Possible alternative. This was not implemented.
abstract class Cloneable
{
public abstract Cloneable Clone();
}
class Digit : Cloneable
{
public override Cloneable Clone()
{
return this.Clone();
}
public new Digit Clone() // Error: 'Digit' already defines a member called 'Clone' with the same parameter types
{
return this;
}
}
Megoldatlan kérdések
- [ ] Hogyan működnek a funkció használatához lefordított API-k a nyelv régebbi verzióiban?
Tervezési értekezletek
- némi megbeszélés https://github.com/dotnet/roslyn/issues/357.
- https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-01-08.md
- Offline vita a döntésről, amely csak a C# 9.0-s verzióban támogatja az osztálymódszerek felülírását.
C# feature specifications