System.Delegate és a delegate
kulcsszó
Ez a cikk a meghatalmazottakat támogató .NET-osztályokról és arról, hogy ezek hogyan vannak megfeleltetve a delegate
kulcsszónak.
Delegálttípusok definiálása
Kezdjük a "delegálás" kulcsszóval, mert elsősorban ezt fogja használni a meghatalmazottak használata során. A fordító által a kulcsszó használatakor létrehozott kód megfelelteti a delegate
metódushívásokat, amelyek meghívják az osztályok és MulticastDelegate az osztályok tagjaitDelegate.
Meghatalmazási típust a metódusadák definiálásához hasonló szintaxissal definiálhat. Csak adja hozzá a delegate
kulcsszót a definícióhoz.
Továbbra is a List.Sort() metódust használjuk példaként. Az első lépés egy típus létrehozása az összehasonlító meghatalmazott számára:
// From the .NET Core library
// Define the delegate type:
public delegate int Comparison<in T>(T left, T right);
A fordító létrehoz egy osztályt, amely a System.Delegate
használt aláírással egyezik (ebben az esetben egy egész számot visszaadó metódus, amelynek két argumentuma van). Ennek a meghatalmazottnak a típusa.Comparison
A Comparison
meghatalmazott típusa általános típus. Az általános adatokkal kapcsolatos részletekért lásd itt.
Figyelje meg, hogy a szintaxis úgy tűnhet, mintha egy változót deklarál, de valójában egy típust deklarál. Delegálttípusokat definiálhat osztályokon belül, közvetlenül a névtereken belül, vagy akár a globális névtérben is.
Feljegyzés
Nem ajánlott deklarálni a delegált típusokat (vagy más típusokat) közvetlenül a globális névtérben.
A fordító emellett hozzáadja és eltávolítja az ehhez az új típushoz tartozó kezelőket, hogy az osztály ügyfelei metódusokat vegyenek fel és távolítsanak el egy példány meghívási listájából. A fordító kikényszeríti, hogy a hozzáadott vagy eltávolított metódus aláírása megegyezik a metódus deklarálásakor használt aláírással.
Meghatalmazottpéldányok deklarálása
A meghatalmazott definiálása után létrehozhat egy ilyen típusú példányt. A C#-ban lévő összes változóhoz hasonlóan a delegált példányokat sem közvetlenül névtérben, sem globális névtérben nem deklarálhatja.
// inside a class definition:
// Declare an instance of that type:
public Comparison<T> comparator;
A változó típusa a Comparison<T>
korábban definiált delegálási típus. A változó neve .comparator
A fenti kódrészlet tagváltozót deklarált egy osztályon belül. Deklarálhat delegált változókat is, amelyek helyi változók, vagy argumentumok a metódusokhoz.
Meghatalmazottak meghívása
A meghatalmazott meghívási listájában szereplő metódusokat a meghatalmazott meghívásával hívhatja meg. A metóduson belül a Sort()
kód meghívja az összehasonlító metódust az objektumok elhelyezésének sorrendjének meghatározásához:
int result = comparator(left, right);
A fenti sorban a kód meghívja a meghatalmazotthoz csatolt metódust. A változót metódusnévként kezeli, és normál metódushívási szintaxissal hívja meg.
Ez a kódsor nem biztonságos feltételezés: Nincs garancia arra, hogy a delegálthoz hozzáadtak egy célt. Ha nem csatoltak célokat, a fenti sor dobást okozna NullReferenceException
. A probléma megoldásához használt kifejezések bonyolultabbak, mint egy egyszerű null-ellenőrzés, és a sorozat későbbi részében szerepelnek.
Meghívási célok hozzárendelése, hozzáadása és eltávolítása
Így van definiálva egy delegálttípus, valamint a delegált példányok deklarálása és meghívása.
A metódust használni List.Sort()
kívánó fejlesztőknek meg kell határozniuk egy metódust, amelynek aláírása megegyezik a delegált típusdefinícióval, és hozzá kell rendelni a rendezési módszer által használt delegálthoz. Ez a hozzárendelés hozzáadja a metódust a delegált objektum meghívási listájához.
Tegyük fel, hogy a sztringek listáját a hosszuk szerint szeretné rendezni. Az összehasonlító függvény a következő lehet:
private static int CompareLength(string left, string right) =>
left.Length.CompareTo(right.Length);
A metódus privát metódusként van deklarálva. Ez rendben van. Előfordulhat, hogy nem szeretné, hogy ez a módszer a nyilvános felület része legyen. Delegálthoz csatolva továbbra is használható összehasonlítási módszerként. A hívó kód ezt a metódust csatolja a delegált objektum céllistájához, és ezen a meghatalmazotton keresztül érheti el.
Ezt a kapcsolatot úgy hozhatja létre, hogy átadja ezt a metódust a List.Sort()
metódusnak:
phrases.Sort(CompareLength);
Figyelje meg, hogy a metódus nevét zárójelek nélkül használja a rendszer. A metódus argumentumként való használata arra utasítja a fordítót, hogy konvertálja a metódushivatkozást egy delegált meghívási célként használható hivatkozássá, és ezt a metódust hívási célként csatolja.
Egy típusváltozó Comparison<string>
deklarálásával és egy hozzárendeléssel is explicit lehetett volna:
Comparison<string> comparer = CompareLength;
phrases.Sort(comparer);
Azokban a használatokban, ahol a delegált célként használt metódus egy kis metódus, gyakori, hogy lambda kifejezésszintaxissal hajtja végre a hozzárendelést:
Comparison<string> comparer = (left, right) => left.Length.CompareTo(right.Length);
phrases.Sort(comparer);
A lambda-kifejezések delegált célokhoz való használatát egy későbbi szakasz ismerteti.
A Rendezés() példa általában egyetlen célmetódust csatol a meghatalmazotthoz. A delegált objektumok azonban támogatják a delegált objektumhoz több célmetódussal rendelkező meghívási listákat.
Delegált és csoportos küldésűdelegate osztályok
A fent ismertetett nyelvi támogatás biztosítja azokat a funkciókat és támogatást, amelyeket általában a meghatalmazottakkal kell dolgoznia. Ezek a funkciók a .NET Core keretrendszer két osztályára épülnek: Delegate és MulticastDelegate.
Az System.Delegate
osztály és annak egyetlen közvetlen alosztálya System.MulticastDelegate
biztosítja a keretrendszer támogatását a meghatalmazottak létrehozásához, a metódusok delegált célként való regisztrálásához és a delegált célként regisztrált összes metódus meghívásához.
Érdekes, hogy az osztályok és System.MulticastDelegate
az System.Delegate
osztályok maguk nem delegált típusok. Ezek biztosítják az összes konkrét delegálttípus alapjait. Ugyanez a nyelvi tervezési folyamat előírta, hogy nem deklarálhat egy osztályt, amely származik Delegate
vagy MulticastDelegate
. A C#-nyelvi szabályok tiltják.
Ehelyett a C#-fordító létrehozza a C# nyelv kulcsszóval deklarált deklarált típusokból származtatott MulticastDelegate
osztálypéldányokat.
Ez a kialakítás a C# és a .NET első kiadásában gyökerezik. A tervezőcsapat egyik célja annak biztosítása volt, hogy a nyelv megkövetelje a típusbiztonságot a meghatalmazottak használata során. Ez azt jelentette, hogy a meghatalmazottak a megfelelő típusú és számú argumentummal legyenek meghívva. És hogy minden visszatérési típus helyesen lett jelezve a fordításkor. A meghatalmazottak az 1.0 .NET-kiadás részét képezték, amely az általános verziók előtt volt.
Az ilyen típusú biztonság érvényesítésének legjobb módja az volt, hogy a fordító létrehozza azokat a konkrét delegált osztályokat, amelyek a használt metódus-aláírást képviselték.
Annak ellenére, hogy közvetlenül nem hozhat létre származtatott osztályokat, az ezekben az osztályokban definiált metódusokat fogja használni. Tekintsük át a meghatalmazottak használatakor használt leggyakoribb módszereket.
Az első, legfontosabb, hogy ne feledje, hogy minden meghatalmazott, akivel dolgozik, a forrásból MulticastDelegate
származik. A csoportos küldési meghatalmazott azt jelenti, hogy egy meghatalmazotton keresztül történő meghíváskor több metóduscél is meghívható. Az eredeti kialakítás különbséget tett a meghatalmazottak között, ahol csak egy célmetódus csatolható és hívható meg, valamint olyan meghatalmazottak között, ahol több célmetódus is csatolható és meghívható. Ez a különbség a gyakorlatban kevésbé volt hasznos, mint eredetileg gondolták. A két különböző osztály már létrejött, és a kezdeti nyilvános kiadás óta a keretrendszerben van.
A meghatalmazottak által leggyakrabban használt metódusok a következők Invoke()
: és BeginInvoke()
/ EndInvoke()
. Invoke()
meghívja az adott meghatalmazott példányhoz csatolt összes metódust. Ahogy fentebb láthatta, általában a delegált változó metódushívási szintaxisával hív meg meghatalmazottakat. Ahogy a sorozat későbbi részében látni fogja, vannak olyan minták, amelyek közvetlenül ezekkel a módszerekkel működnek.
Most, hogy megismerte a nyelvi szintaxist és azokat az osztályokat, amelyek támogatják a meghatalmazottakat, vizsgáljuk meg, hogy milyen erősen gépelt meghatalmazottakat használunk, hozunk létre és hívunk meg.