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.
20.1 Általános
A delegált deklaráció az osztályból System.Delegate
származtatott osztályt határoz meg. A delegált példányok egy meghívási listát foglalnak össze, amely egy vagy több metódus listája, amelyek mindegyike hívható entitásnak minősül. A meghívható entitások például egy példányból és egy metódusból állnak az adott példányon. Statikus metódusok esetén a hívható entitások csak egy metódusból állnak. Ha egy delegált példányt megfelelő argumentumkészlettel hív meg, a meghatalmazott minden meghívható entitását meghívja az adott argumentumkészlettel.
Megjegyzés: A delegált példány érdekes és hasznos tulajdonsága, hogy nem ismeri és nem is érdekli az általa beágyazott metódusok osztályai; csak az számít, hogy ezek a metódusok kompatibilisek legyenek (20.4. §) a meghatalmazott típusával. Ez tökéletesen alkalmassá teszi a meghatalmazottakat a "névtelen" meghívásra. végjegyzet
20.2 Deklarációk deklarálása
A delegate_declaration egy type_declaration (14.7.§), amely új meghatalmazotttípust deklarál.
delegate_declaration
: attributes? delegate_modifier* 'delegate' return_type delegate_header
| attributes? delegate_modifier* 'delegate' ref_kind ref_return_type
delegate_header
;
delegate_header
: identifier '(' parameter_list? ')' ';'
| identifier variant_type_parameter_list '(' parameter_list? ')'
type_parameter_constraints_clause* ';'
;
delegate_modifier
: 'new'
| 'public'
| 'protected'
| 'internal'
| 'private'
| unsafe_modifier // unsafe code support
;
unsafe_modifier a 23.2.
Fordítási időhiba, hogy ugyanaz a módosító többször is megjelenik egy delegált deklarációban.
A variant_type_parameter_list meghatalmazási deklaráció általános deklaráció. Ezenkívül az általános osztálydeklarációkba vagy általános strukturálási deklarációkba beágyazott meghatalmazottak maguk is általános delegált deklarációk, mivel a típusargumentumokat a tárolótípus típusargumentumaival kell létrehozni egy létrehozott típust (8.4. §).
A new
módosító csak egy másik típuson belül deklarált meghatalmazottak esetében engedélyezett, ebben az esetben azt határozza meg, hogy az ilyen meghatalmazott az örökölt tagot a 15.3.5.
A public
delegált típus akadálymentességét a , protected
, internal
és private
módosítók vezérli. A delegált deklaráció kontextusától függően előfordulhat, hogy egyes módosítók nem engedélyezettek (7.5.2. §).
A meghatalmazott típusneve azonosító.
A metódusokhoz hasonlóan (15.6.1. §) ha ref
van, a meghatalmazott ref-ként ad vissza; ellenkező esetben, ha return_type , void
a meghatalmazott nem értéket ad vissza, ellenkező esetben a meghatalmazott érték szerint adja vissza.
Az opcionális parameter_list a meghatalmazott paramétereit adja meg.
A delegált által visszaadott vagy visszaadott deklaráció return_type határozza meg a meghatalmazott által visszaadott eredmény típusát, ha van ilyen.
A visszaadott delegált deklaráció ref_return_type a meghatalmazott által visszaadott variable_reference (9.5. §) által hivatkozott változó típusát határozza meg.
Az opcionális variant_type_parameter_list (18.2.3. §) a meghatalmazott típusparamétereit határozza meg.
A delegált típus visszatérési típusa vagy void
kimenetbiztos (18.2.3.2. §).
A delegált típus minden paramétertípusának bemenetbiztosnak kell lennie (18.2.3.2. §). Ezenkívül minden kimeneti vagy referenciaparaméter-típusnak kimenetbiztosnak kell lennie.
Megjegyzés: A kimeneti paramétereknek bemenetbiztosnak kell lenniük a gyakori megvalósítási korlátozások miatt. végjegyzet
Ezenkívül minden osztálytípus-megkötésnek, interfésztípus-korlátozásnak és típusparaméter-kényszernek a meghatalmazott bármely típusparaméterén bemenetbiztosnak kell lennie.
A C# delegálttípusai névegyenlegek, szerkezetileg nem egyenértékűek.
Példa:
delegate int D1(int i, double d); delegate int D2(int c, double d);
A delegált típusok
D1
D2
két különböző típusból állnak, így azonos aláírásuk ellenére nem cserélhetők fel.záró példa
A többi általános típusdeklarációhoz hasonlóan a típusargumentumokat is meg kell adni egy konstruált delegálási típus létrehozásához. A létrehozott delegálttípus paramétertípusai és visszatérési típusa a delegálási deklaráció minden típusparaméteréhez a létrehozott delegálttípus megfelelő típusargumentumának helyettesítésével jön létre.
A delegált típus deklarálásának egyetlen módja egy delegate_declaration. Minden delegált típus egy referenciatípus, amely a forrásból System.Delegate
származik. Az egyes meghatalmazotti típusokhoz szükséges tagokat a 20.3. A delegálási típusok implicitek sealed
, ezért nem lehet bármilyen típust levezetni egy delegált típusból. Nem delegált osztálytípus System.Delegate
deklarálása sem megengedett.
System.Delegate
önmagában nem delegált típus; ez egy osztálytípus, amelyből az összes delegált típus származik.
20.3 Tagok delegálása
Minden meghatalmazotttípus a Delegate
15.3.4. Ezenkívül minden delegálttípusnak rendelkeznie kell egy nem általános Invoke
metódussal, amelynek paraméterlistája megegyezik a delegált deklarációban szereplő parameter_list, amelynek visszatérési típusa megegyezik a delegált deklarációban szereplő return_type vagy ref_return_type, valamint a delegált deklarációban szereplő ref_kind visszatérési meghatalmazottak esetében. A Invoke
módszernek legalább olyan hozzáférhetőnek kell lennie, mint a meghatalmazást tartalmazó típus. A Invoke
metódus delegálási típuson való meghívása szemantikailag egyenértékű a delegálási hívás szintaxisának használatával (20.6.§).
A megvalósítások további tagokat határozhatnak meg a delegált típusban.
A példányosítás kivételével az osztályra vagy osztálypéldányra alkalmazható műveletek egy delegált osztályra vagy példányra is alkalmazhatók. A típus tagjait System.Delegate
a szokásos taghozzáférés-szintaxissal lehet elérni.
20.4 Meghatalmazotti kompatibilitás
A metódus vagy a delegálás típusa M
kompatibilis a delegált típussalD
, ha az alábbiak mindegyike igaz:
-
D
ésM
ugyanazzal a paraméterszámmal rendelkezik, és minden paraméterbenD
ugyanaz a referenciaparaméter-módosító található, mint a megfelelő paraméterben.M
- Minden értékparaméter esetében identitásátalakítás (10.2.2.2. §) vagy implicit referenciakonvertálás (10.2.8. §) létezik a paramétertípustól
D
a megfelelő paramétertípusig a következőbenM
: . - Az egyes referenciaparaméterek paramétertípusa
D
megegyezik a paraméter típusávalM
. - Az alábbiak egyike igaz:
-
D
ésM
egyaránt értéket nem ad vissza. -
D
ésM
értéket ad vissza (§15.6.1, §20.2), és egy identitás- vagy implicit referenciaátalakítás létezik a visszatérésiM
típustól a visszatérési típusigD
. -
D
ésM
mindkettő visszatérési értéke a ref, az identitásátalakítás a visszatérésiM
típus és a visszatérésiD
típus között létezik, és mindkettő ugyanazzal a ref_kind rendelkezik.
-
A kompatibilitás ezen definíciója lehetővé teszi a visszatérési típus kovarianciáját, a paramétertípusokban pedig a contravariance-t.
Példa:
delegate int D1(int i, double d); delegate int D2(int c, double d); delegate object D3(string s); class A { public static int M1(int a, double b) {...} } class B { public static int M1(int f, double g) {...} public static void M2(int k, double l) {...} public static int M3(int g) {...} public static void M4(int g) {...} public static object M5(string s) {...} public static int[] M6(object o) {...} }
A metódusok
A.M1
ésB.M1
kompatibilisek a delegált típusokkalD1
ésD2
– mivel ugyanazzal a visszatérési típussal és paraméterlistával rendelkeznek. A metódusokB.M2
nemB.M3
B.M4
kompatibilisek a delegált típusokkalD1
, ésD2
mivel különböző visszatérési típusokkal vagy paraméterlistákkal rendelkeznek. A metódusokB.M5
ésB.M6
mindkettő kompatibilis a delegált típussalD3
.záró példa
Példa:
delegate bool Predicate<T>(T value); class X { static bool F(int i) {...} static bool G(string s) {...} }
A metódus
X.F
kompatibilis a delegálás típusávalPredicate<int>
, a metódusX.G
pedig a delegálás típusávalPredicate<string>
.záró példa
Megjegyzés: A delegálási kompatibilitás intuitív jelentése, hogy egy metódus kompatibilis a delegált típussal, ha a delegált minden meghívása lecserélhető a metódus meghívására anélkül, hogy megsértené a típusbiztonságot, és explicit paraméterekként kezelné az opcionális paramétereket és paramétertömböket. Például a következő kódban:
delegate void Action<T>(T arg); class Test { static void Print(object value) => Console.WriteLine(value); static void Main() { Action<string> log = Print; log("text"); } }
A
Action<string>
delegált típusával, mert aAction<string>
meghatalmazott bármilyen meghívása a metódus érvényes meghívásaHa például a
Print(object value, bool prependTimestamp = false)
, akkor aAction<string>
.végjegyzet
20.5 Meghatalmazotti példány
Egy delegált példányát egy delegate_creation_expression (§12.8.17.6) hozza létre, egy delegált típusra való átalakítás, egy delegált kombináció vagy egy delegált eltávolítás esetén. Az újonnan létrehozott delegált példány ezután a következő egy vagy több példányra hivatkozik:
- A delegate_creation_expression hivatkozott statikus módszer, vagy
- A célobjektum (amely nem lehet
null
) és a delegate_creation_expression hivatkozott példánymetódus, vagy - Egy másik meghatalmazott (§12.8.17.6).
Példa:
delegate void D(int x); class C { public static void M1(int i) {...} public void M2(int i) {...} } class Test { static void Main() { D cd1 = new D(C.M1); // Static method C t = new C(); D cd2 = new D(t.M2); // Instance method D cd3 = new D(cd2); // Another delegate } }
záró példa
A delegált példány által beágyazott metódusokat meghívó listának nevezzük. Ha egy delegált példányt egyetlen metódusból hoz létre, az beágyazza ezt a metódust, és a meghívási lista csak egy bejegyzést tartalmaz. Ha azonban két nemnull
delegált példányt egyesít, a meghívási listák összefűzve lesznek – a bal operandus, majd a jobb operandus sorrendben – egy új meghívási lista létrehozásához, amely két vagy több bejegyzést tartalmaz.
Ha egyetlen meghatalmazottból hoz létre új meghatalmazottat, az eredményül kapott meghívási lista csak egy bejegyzéssel rendelkezik, amely a forrásmegbízott (§12.8.17.6).
A meghatalmazottak a bináris +
(12.10.5. §) és +=
az operátorok (12.21.4. §) használatával vannak kombinálva. A meghatalmazottak a bináris -
(12.10.6-=
12.21.4. §) használatával eltávolíthatók a meghatalmazottak kombinációjából. A meghatalmazottak az egyenlőség szempontjából összehasonlíthatók (12.12.9. §).
Példa: Az alábbi példa számos meghatalmazott példányosítását és a hozzájuk tartozó meghívási listákat mutatja be:
delegate void D(int x); class C { public static void M1(int i) {...} public static void M2(int i) {...} } class Test { static void Main() { D cd1 = new D(C.M1); // M1 - one entry in invocation list D cd2 = new D(C.M2); // M2 - one entry D cd3 = cd1 + cd2; // M1 + M2 - two entries D cd4 = cd3 + cd1; // M1 + M2 + M1 - three entries D cd5 = cd4 + cd3; // M1 + M2 + M1 + M1 + M2 - five entries D td3 = new D(cd3); // [M1 + M2] - ONE entry in invocation // list, which is itself a list of two methods. D td4 = td3 + cd1; // [M1 + M2] + M1 - two entries D cd6 = cd4 - cd2; // M1 + M1 - two entries in invocation list D td6 = td4 - cd2; // [M1 + M2] + M1 - two entries in invocation list, // but still three methods called, M2 not removed. } }
A példányosításkor
cd1
éscd2
a példányosításkor mindegyik egy metódust foglal magában. Acd3
példányosításkor a rendszer két metódus meghívási listáját tartalmazza,M1
ésM2
ebben a sorrendben.cd4
's invocation list containsM1
,M2
andM1
, in the order. Acd5
meghívási lista ebben a sorrendben tartalmazzaM1
a ,M2
,M1
,M1
ésM2
.Ha egy másik meghatalmazottból hoz létre egy delegate_creation_expression az eredmény egy olyan meghívási listával rendelkezik, amely az eredetitől eltérő struktúrával rendelkezik, de ugyanazt a metódust hívja meg ugyanabban a sorrendben. Ha
td3
a meghívási listábólcd3
jön létre, annak csak egy tagja van, de ez a tag a metódusokM1
listája, ésM2
ezeket a metódusokat a rendszer ugyanabban a sorrendben hívja megtd3
, mint amelyetcd3
a rendszer meghív. Atd4
példányosításhoz hasonlóan a híváslista csak két bejegyzéssel rendelkezik, de a három metódustM1
M2
is meghívja, ésM1
ebben a sorrendben ugyanúgy, ahogycd4
az is.A meghívási lista szerkezete befolyásolja a delegált kivonást. Delegálhat
cd6
, amelyet kivonássalcd2
hoz létre (amely meghívjaM2
) acd4
(meghívóM1
,M2
és ) meghívásokbólM1
ésM1
M1
. A delegálástd6
azonban, amely a kivonássalcd2
(amely meghívM2
)td4
jön létre (amely meghívjaM1
M2
, és ) továbbra is meghívjaM1
,M1
ésM2
M1
ebben a sorrendben, mivelM2
nem egyetlen bejegyzés szerepel a listában, hanem egy beágyazott lista tagja. A meghatalmazottak kombinálására (és eltávolítására) vonatkozó további példákért lásd a 20.6.záró példa
A példányosítás után a meghatalmazott példány mindig ugyanarra a meghívási listára hivatkozik.
Megjegyzés: Ne feledje, hogy ha két meghatalmazottat egyesít, vagy az egyiket eltávolítja a másikból, az új meghatalmazottak saját meghívási listával jelennek meg; az egyesített vagy eltávolított meghatalmazottak meghívási listája változatlan marad. végjegyzet
20.6 Meghatalmazotti meghívás
A C# speciális szintaxist biztosít a meghatalmazott meghívásához. Amikor egy nemnull
delegált példányt hív meg, amelynek meghívási listája egy bejegyzést tartalmaz, meghívja az egyik metódust ugyanazokkal az argumentumokkal, amelyeket adott, és ugyanazt az értéket adja vissza, mint a hivatkozott metódus. (A meghatalmazotti meghívással kapcsolatos részletes információkért lásd 12.8.10.4.) Ha egy ilyen meghatalmazott meghívása során kivétel történik, és ez a kivétel nem szerepel a meghívott metóduson belül, a kivételfogó záradék keresése a meghatalmazottat meghívó metódusban folytatódik, mintha ez a metódus közvetlenül meghívta volna azt a metódust, amelyre az adott meghatalmazott hivatkozott.
Egy delegált példány meghívása, amelynek meghívási listája több bejegyzést tartalmaz, a meghívási listában szereplő metódusok szinkron meghívásával, sorrendben. Az úgynevezett metódusok ugyanazokat az argumentumokat adják át, mint a delegált példánynak. Ha egy ilyen delegált meghívás hivatkozási paramétereket tartalmaz (15.6.2.3.3.3.3. §), minden metódushívás ugyanarra a változóra való hivatkozással történik; a meghívási lista egyik metódusa által a változóra vonatkozó módosítások a meghívási lista metódusai számára is láthatók lesznek. Ha a delegált meghívás kimeneti paramétereket vagy visszatérési értéket tartalmaz, a végső érték a lista utolsó meghatalmazottjának meghívásából származik. Ha egy ilyen meghatalmazott meghívásának feldolgozása során kivétel történik, és ez a kivétel nem jelenik meg a meghívott metóduson belül, a kivételfogási záradék keresése folytatódik a meghatalmazottat meghívó metódusban, és a meghívási lista további metódusai nem lesznek meghívva.
Olyan delegált példány meghívása, amelynek értéke null
típuskivételt System.NullReferenceException
eredményez.
Példa: Az alábbi példa a meghatalmazottak példányosítását, egyesítését, eltávolítását és meghívását mutatja be:
delegate void D(int x); class C { public static void M1(int i) => Console.WriteLine("C.M1: " + i); public static void M2(int i) => Console.WriteLine("C.M2: " + i); public void M3(int i) => Console.WriteLine("C.M3: " + i); } class Test { static void Main() { D cd1 = new D(C.M1); cd1(-1); // call M1 D cd2 = new D(C.M2); cd2(-2); // call M2 D cd3 = cd1 + cd2; cd3(10); // call M1 then M2 cd3 += cd1; cd3(20); // call M1, M2, then M1 C c = new C(); D cd4 = new D(c.M3); cd3 += cd4; cd3(30); // call M1, M2, M1, then M3 cd3 -= cd1; // remove last M1 cd3(40); // call M1, M2, then M3 cd3 -= cd4; cd3(50); // call M1 then M2 cd3 -= cd2; cd3(60); // call M1 cd3 -= cd2; // impossible removal is benign cd3(60); // call M1 cd3 -= cd1; // invocation list is empty so cd3 is null // cd3(70); // System.NullReferenceException thrown cd3 -= cd1; // impossible removal is benign } }
Ahogy az az utasításban
cd3 += cd1;
is látható, a meghatalmazottak többször is jelen lehetnek egy meghívási listában. Ebben az esetben csak egyszer hívjuk meg előfordulásonként. Egy ilyen meghívási listában a meghatalmazott eltávolításakor a meghívási listában az utolsó előfordulás az, amelyik ténylegesen el lett távolítva.Közvetlenül a végleges utasítás
cd3 -= cd1
végrehajtása előtt a meghatalmazottcd3
egy üres híváslistára hivatkozik. Ha megkísérli eltávolítani a meghatalmazottat egy üres listából (vagy nem létező meghatalmazottat szeretne eltávolítani egy nem üres listáról), az nem hiba.A létrehozott kimenet a következő:
C.M1: -1 C.M2: -2 C.M1: 10 C.M2: 10 C.M1: 20 C.M2: 20 C.M1: 20 C.M1: 30 C.M2: 30 C.M1: 30 C.M3: 30 C.M1: 40 C.M2: 40 C.M3: 40 C.M1: 50 C.M2: 50 C.M1: 60 C.M1: 60
záró példa
ECMA C# draft specification