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.
19.1 Általános
Az interfész egy szerződést határoz meg. Az interfészt megvalósító osztálynak vagy szerkezetnek be kell tartania a szerződését. Egy interfész több alapillesztőtől örökölhet, az osztály vagy a szerkezet pedig több interfészt is implementálhat.
Az interfészek a 19.4. §-ban leírtak szerint különböző tagokat tartalmazhatnak. Maga a felület implementációt biztosíthat az általa deklarált függvénytagok egy részének vagy mindegyikének. Azok a tagok, amelyek esetében az interfész nem biztosít implementációt, absztraktak. Az implementációkat az interfészt megvalósító osztályoknak vagy szerkezeteknek kell szolgáltatniuk, vagy olyan származtatott interfésznek kell lenniük, amelyek felülíró definíciót biztosítanak.
Megjegyzés: Korábban egy új függvénytag hozzáadása egy interfészhez hatással volt az adott felülettípus összes meglévő felhasználójára; ez egy törés változás. Az interfészfüggvény tag implementációinak hozzáadása lehetővé tette a fejlesztők számára, hogy frissítsenek egy felületet, miközben a implementátorok továbbra is felülbírálhatják az implementációt. A felület felhasználói nem kompatibilitástörő változásként fogadhatják el a megvalósítást; ha azonban eltérőek a követelmények, felülbírálhatják a megadott implementációkat. végjegyzet
19.2 Interfész deklarációk
19.2.1 Általános
A interface_declaration egy type_declaration (14.7.§), amely új interfésztípust deklarál.
interface_declaration
: attributes? interface_modifier* 'partial'? 'interface'
identifier variant_type_parameter_list? interface_base?
type_parameter_constraints_clause* interface_body ';'?
;
A interface_declarationegy választható attribútumkészletből (23. §), majd egy választható interface_modifier-készletből(19.2.2. §), majd egy választható részleges módosítóból (15.2.7. §) áll, amelyet a kulcsszó interface és az interfész nevét tartalmazó azonosító követ, variant_type_parameter_list opcionális specifikáció (19.2.3. §), amelyet egy opcionális interface_base specifikáció követ (19.2.4. §)), majd egy választható type_parameter_constraints_clausespecifikáció (15.2.5.§), majd egy interface_body (19.3. §), amelyet opcionálisan pontosvessző követ.
Egy interfész nyilatkozat nem szolgáltathat type_parameter_constraints_clauses-t, kivéve, ha egy variant_type_parameter_listis megadott.
Egy felületi deklaráció, amely biztosít egy variant_type_parameter_list-et, generikus felületi deklaráció. Ezenkívül az általános osztálydeklarációkba vagy általános szerkezetdeklarációkba ágyazott interfészek maguk is általános felületi deklarációk, mivel a típusargumentumokat a tárolótípus típusargumentumait kell megadni egy beépített típus létrehozásához (8.4. §).
19.2.2 Felületmódosítók
Egy interface_declaration opcionálisan tartalmazhat felületmódosítók sorozatát:
interface_modifier
: 'new'
| 'public'
| 'protected'
| 'internal'
| 'private'
| unsafe_modifier // unsafe code support
;
unsafe_modifier (24.2. §) csak nem biztonságos kódban érhető el (24. §).
Fordítási időhiba, hogy ugyanaz a módosító többször is megjelenik egy felületi deklarációban.
A new módosító csak az osztályon belül definiált felületeken engedélyezett. Azt határozza meg, hogy a felület elrejti az azonos nevű örökölt elemet, ahogyan az a 15.3.5 szakaszban le van írva.
A public, protected, internalés private módosítók szabályozzák a felület akadálymentességét. Attól függően, hogy milyen környezetben történik az interfész deklarációja, ezen módosítók közül csak néhány engedélyezhető (7.5.2. §). Ha egy részleges típusdeklaráció (§15.2.7) tartalmaz egy hozzáférési specifikációt (a public, protected, internal és private módosítókon keresztül), a §15.2.2 szabályai érvényesek.
19.2.3 Variant type parameter lists
19.2.3.1 Általános
A variánstípus paraméterlistái csak interfész- és delegálási típusok esetén fordulhatnak elő. A különbség a szokásos típusparaméterlista-khez képest az egyes típusparaméterek opcionális variancia annotációja.
variant_type_parameter_list
: '<' variant_type_parameter (',' variant_type_parameter)* '>'
;
variant_type_parameter
: attributes? variance_annotation? type_parameter
;
variance_annotation
: 'in'
| 'out'
;
Ha a variancia széljegyzete azout, a típusparaméter kovarianciánsnak minősül. Ha a variancia széljegyzete az in, a típusparaméter állítólag contravariant. Ha nincs eltérési széljegyzet, a típusparaméter invariánsnak minősül.
Példa: Az alábbiakban:
interface C<out X, in Y, Z> { X M(Y y); Z P { get; set; } }
Xkovariáns,Ykontravariáns ésZinvariáns.záró példa
Ha egy általános interfész több részből áll (15.2.3. §), minden részleges deklarációnak ugyanazt a varianciát kell meghatároznia minden típusparaméterhez.
19.2.3.2 Varianciabiztonság
A variancia-megjegyzések előfordulása egy típus típusparaméter-listájában korlátozza azokat a helyeket, ahol a típusok a típusdeklarációban előfordulhatnak.
A kimenet-biztonságtalan típusú T esetén, ha az alábbiak egyike fennáll:
-
Tegy contravariant típusú paraméter -
Tegy olyan tömbtípus, amely kimenet szempontjából nem biztonságos elemtípussal rendelkezik -
Tegy interfész vagy delegáti típus, amely egy általános típusbólSᵢ,... Aₑlett létrehozvaS<Xᵢ, ... Xₑ>, ahol az alábbi lehetőségek közül legalább egyAᵢteljesül:-
Xᵢkovariáns vagy invariáns, ésAᵢnem biztonságos a kimenete. -
Xᵢcontravariant vagy invariáns, ésAᵢbemeneti-nem biztonságos.
-
A T típus bemenete nem biztonságos , ha az alábbiak egyike rendelkezik:
-
Tkovariant típusú paraméter -
Tolyan tömbtípus, amely bemeneti-nem biztonságos elemtípussal rendelkezik -
Tegy interfész vagy delegáti típus, amely egy általános típusbólS<Aᵢ,... Aₑ>lett létrehozvaS<Xᵢ, ... Xₑ>, ahol az alábbi lehetőségek közül legalább egyAᵢteljesül:-
Xᵢcovariáns vagy invariáns, ésAᵢbemenet szempontjából nem biztonságos. -
Xᵢcontravariant vagy invariáns, ésAᵢkimenete nem biztonságos.
-
Intuitív módon, a kimeneti pozícióban a kimeneti szempontból nem biztonságos típus tilos, és a bemeneti pozícióban a bemeneti szempontból nem biztonságos típus nem megengedett.
A típus kimenetbiztos, ha nem kimenet-nem biztonságos, és bemenet-biztonságos, ha nem bemeneti-nem biztonságos.
19.2.3.3 Variancia-átalakítás
A varianciajegyzetek célja, hogy megengedőbb (de mégis típusbiztos) átalakításokat biztosítson az interfész- és delegációs típusokra. E célból az implicit (10.2. §) és explicit konverziók (10.3. §) definíciói a variancia-konvertálhatóság fogalmát használják, amely a következőképpen van definiálva:
A típus T<Aᵢ, ..., Aᵥ> variancia-átalakítható típussá T<Bᵢ, ..., Bᵥ> , ha T egy interfész vagy egy delegált típus, amelyet a variánstípus paramétereivel deklaráltak T<Xᵢ, ..., Xᵥ>, és minden egyes változattípus-paraméterhez Xᵢ az alábbiak egyike tartozik:
-
Xᵢkovariáns, és létezik egy implicit hivatkozás vagy identitásátalakításAᵢ-bőlBᵢ-be. -
Xᵢkontravariáns, és létezik egy implicit hivatkozás vagy identitás konverzióBᵢ-rőlAᵢ-re. invariáns, és van egy identitásátalakítás a -ból .
19.2.4 Alapfelületek
Az interfészek örökölhetnek nulla vagy több interfésztípust, amelyeket az interfész explicit alapfelületénekneveznek. Ha egy interfész egy vagy több explicit alapinterfésszel rendelkezik, akkor az interfész-azonosítót kettőspont és vesszővel tagolt alapinterfész-típusok listája következik.
A származtatott interfészek deklarálhatnak olyan új tagokat, amelyek elrejtik az örökölt tagokat (7.7.2.3. §) a bázisfelületeken deklarálva, vagy explicit módon implementálják az örökölt tagokat (19.6.2. §) a bázisfelületeken.
interface_base
: ':' interface_type_list
;
Az explicit alapillesztők felépíthetők interfésztípusok (8.4. §, 19.2. §). Az alapfelület önmagában nem lehet típusparaméter, de magában foglalhatja a hatókörben lévő típusparamétereket is.
A létrehozott interfésztípusok esetében az explicit alapinterfészek úgy jönnek létre, hogy az általános típusdeklarációkon szereplő explicit alapinterfész deklarációit veszik alapul, és az alapinterfész-deklarációban szereplő type_parameter helyére a létrehozott típus megfelelő type_argument-ja kerül.
Az interfész explicit alapillesztőinek legalább olyan akadálymentesnek kell lenniük, mint maga az interfész (7.5.5. §).
Megjegyzés: Például fordítási hibát okoz, ha egy
privatevagyinternalinterfészt ad meg egy interface_base elemhez egypublicinterfészben. végjegyzet
Fordítási idejű hiba, ha egy interfész közvetlenül vagy közvetve örökli saját magától.
Az interfészek alapfelületeiaz explicit alapillesztők és azok alapillesztői. Más szóval, az alapinterfészek készlete az explicit alapinterfészek, azok explicit alapinterfészeinek teljes tranzitív lezárása és így tovább. Az interfész örökli az alapfelületek összes tagját.
Példa: Az alábbi kódban
interface IControl { void Paint(); } interface ITextBox : IControl { void SetText(string text); } interface IListBox : IControl { void SetItems(string[] items); } interface IComboBox: ITextBox, IListBox {}Az alapfelületek a
IComboBox,IControl,ITextBoxésIListBox. Más szóval, aIComboBoxfenti felület örökli a tagokatSetTextésSetItems, valamintPaintis.záró példa
A létrehozott általános típusból öröklő tagok a típushelyettesítés után öröklődnek. Ez azt jelzi, hogy a tag összes összetevőtípusa az alaposztály-deklaráció típusparamétereit a class_base specifikációban használt megfelelő típusargumentumokra cseréli.
Példa: Az alábbi kódban
interface IBase<T> { T[] Combine(T a, T b); } interface IDerived : IBase<string[,]> { // Inherited: string[][,] Combine(string[,] a, string[,] b); }a felület
IDeriveda típusparaméterCombinelecserélése után örökli aTmetóduststring[,].záró példa
Az interfészt megvalósító osztály vagy szerkezet implicit módon implementálja az interfész összes alapillesztőjét is.
A részleges interfész deklaráció több részén található interfészek kezeléséről (15.2.7. §) részletesen a 15.2.4.3. fejezet tárgyalja.
Az illesztőfelület minden alapfelületének kimeneti biztonságosnak kell lennie (19.2.3.2. §).
19.3 Interfész törzse
Az interfész interface_body határozza meg a felület tagjait.
interface_body
: '{' interface_member_declaration* '}'
;
19.4 Interfésztagok
19.4.1 Általános
Az interfészek tagjai az alapfelületektől örökölt tagok, és a felület által deklarált tagok.
interface_member_declaration
: constant_declaration
| field_declaration
| method_declaration
| property_declaration
| event_declaration
| indexer_declaration
| static_constructor_declaration
| operator_declaration
| type_declaration
;
Ez a záradék kibővíti az osztályok tagjainak leírását (15.3. §) az interfészekre vonatkozó korlátozásokkal. A felülettagok deklarálása member_declarationhasználatával történik a következő további szabályokkal:
- A finalizer_declaration nem engedélyezett.
- A példánykonstruktorok ( constructor_declarations) nem engedélyezettek.
- Minden felületi tag implicit módon rendelkezik nyilvános hozzáféréssel; azonban a statikus konstruktorok kivételével explicit hozzáférés-módosító (7.5.2. §) engedélyezett (15.12. §).
- A
abstractmódosító a test nélküli interfészfüggvény-tagokra utal; ez a módosító explicit módon adható meg. - Az a felületpéldány-függvénytag, amelynek deklarációja tartalmaz egy törzset, implicit tag
virtual, kivéve, ha a módosító vagysealedaprivatemódosító van használatban. Avirtualmódosító explicit módon adható meg. - Az
privateinterfész egy vagysealedtöbb tagjának rendelkeznie kell egy szervvel. - A
privatefüggvénytagok nem rendelkeznek a módosítóvalsealed. - A származtatott felület felülbírálhatja az alapillesztőben deklarált absztrakt vagy virtuális tagot.
- A kifejezetten megvalósított függvénytagok nem rendelkeznek a módosítóval
sealed.
Egyes deklarációk, például a constant_declaration (15.4. §) nem korlátozzák az interfészeket.
Az interfész öröklött tagjai kifejezetten nem részei az interfész deklarációs terének. Így a felület lehetővé teszi, hogy deklaráljon egy olyan tagot, amelynek neve vagy aláírása megegyezik az örökölt tag nevével vagy aláírásával. Ha ez történik, a származtatott illesztőtag azt mondja, hogy elrejtse az alap illesztőtagot. Az örökölt tag elrejtése nem minősül hibának, de figyelmeztetést eredményez (7.7.2.3. §).
Ha egy new módosító szerepel egy olyan deklarációban, amely nem rejt el öröklött tagot, a rendszer ennek megfelelően figyelmeztetést ad ki.
Megjegyzés: Az osztály
objecttagjai szigorúan nem tagjai semmilyen felületnek (19.4. §). Az osztályobjecttagjai azonban bármely felülettípusban elérhetőek a tagok keresésével (12.5. §). végjegyzet
A többrészesen deklarált felület tagjainak halmaza (15.2.7. §) az egyes részekben deklarált tagok egysége. Az interfész-nyilatkozat minden részének szervei azonos deklarációs térrel (7.3. §) osztoznak, és az egyes tagok hatóköre (7.7. §) az összes rész testületére kiterjed.
Példa: Fontolja meg egy tag és egy
IAtulajdonságMimplementációját tartalmazó felületetP. A implementálási típusCnem biztosít implementációt egyikhez semMP. Azokat olyan hivatkozáson keresztül kell elérni, amelynek fordítási ideje olyan felület, amely implicit módon átalakíthatóIAIBa vagy a . Ezek a tagok nem találhatók meg a tagkeresés során egy változó típusúCváltozón.interface IA { public int P { get { return 10; } } public void M() { Console.WriteLine("IA.M"); } } interface IB : IA { public new int P { get { return 20; } } void IA.M() { Console.WriteLine("IB.M"); } } class C : IB { } class Test { public static void Main() { C c = new C(); ((IA)c).M(); // cast needed Console.WriteLine($"IA.P = {((IA)c).P}"); // cast needed Console.WriteLine($"IB.P = {((IB)c).P}"); // cast needed } }A felületeken
IAIBbelül a tagMközvetlenül név szerint érhető el. A metódusonMainbelül azonban nem tudunk írnic.M()vagyc.P, mivel ezek a nevek nem láthatók. A keresésükhöz a megfelelő felülettípusra kell leadni őket. A deklaráció explicitMfelület implementálásiIBszintaxist használ. Erre azért van szükség, hogy ez a metódus felülbírálja az egyiket;IAa módosítóoverridenem alkalmazható egy függvénytagra. záró példa
19.4.2 Interfészmezők
Ez a záradék kibővíti a felületeken deklarált mezők §15.5 osztályában lévő mezők leírását.
A felületmezők deklarálása field_declarationhasználatával történik (15.5.1. §) a következő további szabályokkal:
- A példánymező deklarálása field_declaration fordítási idő hibája.
Példa: A következő program különböző típusú statikus tagokat tartalmaz:
public interface IX { public const int Constant = 100; protected static int field; static IX() { Console.WriteLine("static members initialized"); Console.WriteLine($"constant = {IX.Constant}, field = {IX.field}"); field = 50; Console.WriteLine("static constructor has run"); } } public class Test: IX { public static void Main() { Console.WriteLine($"constant = {IX.Constant}, field = {IX.field}"); } }A létrehozott kimenet a következő:
static members initialized constant = 100, field = 0 static constructor has run constant = 100, field = 50záró példa
A statikus mezők kiosztásával és inicializálásával kapcsolatos információkért lásd a 19.4.8 .
19.4.3 Felületi módszerek
Ez a záradék a felületeken deklarált metódusok 15.6. osztályában lévő metódusok leírását egészíti ki.
A felületi metódusok method_declarationhasználatával vannak deklarálva (15.6.§)). Az illesztőmetódus-deklaráció attribútumai, return_type, ref_return_type, azonosítója és parameter_list ugyanazzal a jelentéssel rendelkeznek, mint egy osztályban lévő metódusdeklarációé. A felületi metódusok a következő további szabályokkal rendelkeznek:
method_modifier nem terjed ki
override.Olyan módszer, amelynek törzse kettőspont (
;)abstract; aabstractmódosító nem szükséges, de engedélyezett.Olyan felületmetódus-deklaráció, amelynek blokktörzse vagy kifejezéstörzse method_body;
virtualavirtualmódosító nem kötelező, de engedélyezett.A method_declaration csak akkor type_parameter_constraints_clause s, ha type_parameter_list is rendelkezik.
Az osztálymetódushoz megadott módosítók érvényes kombinációira vonatkozó követelmények listája az alábbiak szerint bővül:
- A nem kiirtott statikus deklarációnak blokktesttel vagy kifejezéstörzstel kell rendelkeznie method_body.
- A nem kiirtott virtuális deklarációnak blokktesttel vagy kifejezéstörzstel kell rendelkeznie method_body.
- A nem megsemmisített magánbevallásnak method_body kell tartalmaznia egy blokktestet vagy kifejezéstörzset.
- A nem megsemmisített lezárt nyilatkozatnak method_body kell tartalmaznia egy blokktestet vagy kifejezéstörzset.
- Az aszinkron deklarációnak blokktörzset vagy kifejezéstörzset kell tartalmaznia method_body.
Az interfészmetódus minden paramétertípusának bemenetbiztosnak kell lennie (19.2.3.2. §), és a visszatérési típusnak vagy
voidkimenetbiztosnak kell lennie.Bármely 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
A módszer minden típusparaméterére vonatkozó osztálytípus-korlátozásnak, interfésztípus-korlátozásnak és típusparaméter-kényszernek bemenetbiztosnak kell lennie.
Ezek a szabályok biztosítják, hogy az interfész kovariáns vagy kontravariáns használata típusbiztos maradjon.
Példa:
interface I<out T> { void M<U>() where U : T; // Error }A
Ttípusparaméter-korlátozás aU-en történő használata hibás, mert nem biztonságos bemenetként.Ha ez a korlátozás nincs érvényben, a típusbiztonságot a következő módon lehet megsérteni:
interface I<out T> { void M<U>() where U : T; } class B {} class D : B {} class E : B {} class C : I<D> { public void M<D>() {...} } ... I<B> b = new C(); b.M<E>();Ez valójában egy hívás
C.M<E>-ra. De ez a hívás megköveteli, hogy aEaD-ből származzon, így a típusbiztonság sérülne itt.záró példa
Megjegyzés: Lásd a 19.4.2. § -t egy olyan példáért, amely nem csak egy implementációval rendelkező statikus metódust jelenít meg, hanem mivel ezt a metódust meghívják
Main, és a megfelelő visszatérési típussal és aláírással rendelkezik, az is belépési pont. végjegyzet
Az illesztőben deklarált implementációval rendelkező virtuális metódusokat felül lehet bírálni, hogy egy származtatott felületen absztraktak legyenek. Ezt nevezik újraadási műveletnek.
Példa:
interface IA { void M() { Console.WriteLine("IA.M"); } } interface IB: IA { abstract void IA.M(); // reabstraction of M }Ez olyan származtatott felületeken hasznos, ahol egy módszer megvalósítása nem megfelelő, és a végrehajtási osztályoknak megfelelőbb megvalósítást kell biztosítaniuk. záró példa
19.4.4 Interfész tulajdonságai
Ez a záradék a felületeken deklarált tulajdonságok 15.7. osztályában lévő tulajdonságok leírását egészíti ki.
A felülettulajdonságok property_declaration(15.7.1. §) használatával deklarálhatók a következő további szabályokkal:
property_modifier nem terjed ki
override.Az explicit interfésztag-megvalósítás nem tartalmazhat accessor_modifier (15.7.3. §).
A származtatott interfészek explicit módon implementálhatnak egy alapfelületen deklarált absztrakt felületi tulajdonságot.
Megjegyzés: Mivel az illesztő nem tartalmazhat példánymezőket, a felülettulajdonságok nem lehetnek példány automatikus tulajdonságai, mivel ehhez implicit rejtett példánymezők deklarálása szükséges. végjegyzet
Az illesztőtulajdonság típusának kimenetbiztosnak kell lennie, ha van beszerelhető tartozék, és bemenetbiztosnak kell lennie, ha van beállítva tartozék.
Olyan felületmetódus-deklaráció, amelynek blokktörzse vagy kifejezéstörzse method_body;
virtualavirtualmódosító nem kötelező, de engedélyezett.Olyan példány property_declaration , amely nem rendelkezik
abstractimplementációval; aabstractmódosító nem szükséges, de engedélyezett. Soha nem tekinthető automatikusan megvalósított tulajdonságnak (15.7.4. §).
19.4.5 Interfészesemények
Ez a záradék kibővíti a 15.8. osztály eseményeinek leírását a felületeken deklarált események esetében.
Az interfészesemények event_declarationhasználatával vannak deklarálva (15.8.1. §), a következő további szabályokkal:
-
event_modifier nem tartalmazhat.
override - A származtatott interfész egy alapfelületen deklarált absztrakt interfészeseményt valósíthat meg (15.8.5. §).
- Fordítási időhiba, hogy egy példányban variable_declaratorsevent_declaration tartalmazzon variable_initializer.
- A módosítókkal rendelkező
virtualsealedpéldányeseményeknek kiegészítőket kell deklarálniuk. Soha nem tekinthető automatikusan implementált mezőszerű eseménynek (15.8.2. §). - A módosítóval rendelkező
abstractpéldányesemények nem deklarálnak tartozékokat. - Az interfészesemény típusának bemenetbiztosnak kell lennie.
19.4.6 Felületindexelők
Ez a záradék kibővíti az indexelők leírását a 15.9. osztályban az interfészekben deklarált indexelők esetében.
A felületindexelők deklarálása indexer_declarationhasználatával történik (15.9. §), a következő további szabályokkal:
indexer_modifier nem terjed ki
override.Olyan indexer_declaration , amely rendelkezik kifejezéstörzsgel , vagy blokktörzset vagy kifejezéstörzset
virtualtartalmazó tartozékot tartalmaz; avirtualmódosító nem kötelező, de engedélyezett.Olyan indexer_declaration , amelynek kiegészítő teste kettőspont (
;)abstract; aabstractmódosító nem szükséges, de engedélyezett.Az interfész indexelőjének minden paramétertípusának bemenetbiztosnak kell lennie (19.2.3.2. §).
Bármely 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
Az interface indexelő típusának kimenetbiztosnak kell lennie, ha van get hozzáférő, és bemenetbiztosnak kell lennie, ha van set hozzáférő.
19.4.7 Interfész operátorok
Ez a záradék kibővíti operator_declaration tagok leírását a 15.10 .
A felület operator_declaration a megvalósítás (19.1. §).
Fordítási időhiba, amikor egy interfész konverziós, egyenlőségi vagy egyenlőtlenségi operátort deklarál.
19.4.8 Interfész statikus konstruktorok
Ez a záradék kibővíti a statikus konstruktorok leírását az interfészekben deklarált statikus konstruktorok 15.12 .
A zárt (8.4.3.3.§)-illesztő statikus konstruktora legfeljebb egyszer fut egy adott alkalmazástartományban. A statikus konstruktor végrehajtását az alábbi műveletek közül az első aktiválja, amely egy alkalmazástartományon belül történik:
- A rendszer a felület bármely statikus tagjára hivatkozik.
- Mielőtt a
Mainmetódust meghívná egy olyan interfészre, amely tartalmazza azt aMainmetódust (7.1. §), amelyben a végrehajtás megkezdődik. - Ez a felület implementációt biztosít egy tag számára, és a végrehajtás az adott tag legspecifikusabb implementációjaként (19.4.10. §) érhető el.
Megjegyzés: Abban az esetben, ha az előző műveletek egyike sem történik meg, az illesztő statikus konstruktora nem hajtható végre olyan program esetében, amelyben az interfészt megvalósító típusok példányai jönnek létre és használhatók. végjegyzet
Egy új zárt felülettípus inicializálásához először létrejön egy új statikus mezőkészlet az adott zárt típushoz. A statikus mezők mindegyike az alapértelmezett értékre van inicializálva. Ezután a statikus mező inicializálói végre lesznek hajtva ezekhez a statikus mezőkhöz. Végül végrehajtja a statikus konstruktort.
Megjegyzés: Lásd a 19.4.2. §-t a különböző típusú statikus tagok (beleértve a főmetódusokat) egy interfészen belül deklarált használatára. végjegyzet
19.4.9 Beágyazott illesztőtípusok
Ez a záradék kibővíti a beágyazott típusok leírását a 15.3.9 osztályban az interfészekben deklarált beágyazott típusok esetében.
Hiba a variance_annotation deklarált típusparaméter hatókörén belül osztálytípust, szerkezettípust vagy számtípust deklarálni (19.2.3.1. §).
Példa: Az alábbi deklaráció
Cegy hiba.interface IOuter<out T> { class C { } // error: class declaration within scope of variant type parameter 'T' }záró példa
19.4.10 legspecifikusabb megvalósítás
Minden osztálynak és szerkezetnek a legspecifikusabb implementációval kell rendelkeznie minden olyan virtuális tag számára, amelyet az adott típus által implementált összes felületen deklaráltak a típusban vagy annak közvetlen és közvetett interfészeiben megjelenő implementációk között. A legspecifikusabb implementáció egy egyedi implementáció, amely minden más implementációnál pontosabb.
Megjegyzés: A legspecifikusabb végrehajtási szabály biztosítja, hogy a gyémánt felület örökléséből eredő kétértelműséget a programozó explicit módon oldja fel az ütközés helyszínén. végjegyzet
Olyan típus T esetében, amely egy olyan struktúra vagy osztály, amely interfészeket I2 implementál, és I3ahol I2 és I3 mindkettő közvetlenül vagy közvetve származik a tagot Ideklaráló interfészbőlM, a legspecifikusabb megvalósítás M a következő:
- Ha
Ta végrehajtástI.Mdeklarálja, az a legspecifikusabb megvalósítás. - Ellenkező esetben, ha
Tegy osztály és egy közvetlen vagy közvetett alaposztály implementációtI.Mdeklarál, akkor a leglevezetettebb alaposztályTa legspecifikusabb implementáció. - Ellenkező esetben, ha
I2I3a közvetlen vagy közvetett módon megvalósítottTésI3abbólI2származó interfészek konkrétabb megvalósítást jelentenek,I3.MmintI2.Ma . - Ellenkező esetben sem
I2.Ma konkrétabb, semI3.Ma hiba nem jelentkezik.
Példa:
interface IA { void M() { Console.WriteLine("IA.M"); } } interface IB : IA { void IA.M() { Console.WriteLine("IB.M"); } } interface IC: IA { void IA.M() { Console.WriteLine("IC.M"); } } abstract class C: IB, IC { } // error: no most specific implementation for 'IA.M' abstract class D: IA, IB, IC // OK { public abstract void M(); }A legspecifikusabb végrehajtási szabály biztosítja, hogy az ütközést (azaz a gyémánt örökléséből eredő kétértelműséget) a programozó explicit módon oldja meg a konfliktus keletkezésekor. záró példa
19.4.11 Interfésztag-hozzáférés
Az illesztőtagok a taghozzáférés (12.8.7.§) és az indexelőhozzáférés (12.8.12.4. §) kifejezésével I.M érhetők el, és I[A]– ahol I interfésztípus M – az adott interfésztípus állandója, mezője, metódusa, tulajdonsága vagy eseménye, és A indexelő argumentumlista.
A közvetlen vagy közvetett alaposztályú DosztálybanB, ahol B közvetlenül vagy közvetve implementál egy felületetI, és I meghatároz egy metódustM(), a kifejezés base.M() csak akkor érvényes, ha base.M() statikusan (12.3. §) egy osztálytípus implementációjaM().
A szigorúan egyöröklésű felületek (az öröklési lánc minden felülete pontosan nulla vagy egy közvetlen alapfelülettel rendelkezik), a tagkeresés hatása (12.5.§), metódushívás (12.8.1. §) A 0.2) és az indexelő hozzáférés (§12.8.12.4) szabályai pontosan ugyanazok, mint az osztályok és a szerkezetek esetében: A származtatott tagok kevesebb származtatott tagot rejtenek el ugyanazzal a névvel vagy aláírással. A többöröklésű felületek esetében azonban kétértelműség fordulhat elő, ha két vagy több nem kapcsolódó alapfelület azonos nevű vagy aláírású tagokat deklarál. Ez az alcím számos példát mutat be, amelyek közül néhány kétértelműséghez vezet, mások pedig nem. A kétértelműségek megoldásához minden esetben explicit szereplők használhatók.
Példa: Az alábbi kódban
interface IList { int Count { get; set; } } interface ICounter { int Count { get; set; } } interface IListCounter : IList, ICounter {} class C { void Test(IListCounter x) { x.Count = 1; // Error ((IList)x).Count = 1; // Ok, invokes IList.Count.set ((ICounter)x).Count = 1; // Ok, invokes ICounter.Count } }az első utasítás fordítási időbeli hibát okoz, mert a tag keresése
Count-ben (IListCounter) nem egyértelmű. Ahogy a példában látható, a kétértelműséget azxmegfelelő alapinterfész típusra történő átalakításával lehet megoldani. Az ilyen kasztoknak nincs futásidejű költségük – csupán abból állnak, hogy fordításkor a példányt kevésbé specifikus típusként kezelik.záró példa
Példa: Az alábbi kódban
interface IInteger { void Add(int i); } interface IDouble { void Add(double d); } interface INumber : IInteger, IDouble {} class C { void Test(INumber n) { n.Add(1); // Invokes IInteger.Add n.Add(1.0); // Only IDouble.Add is applicable ((IInteger)n).Add(1); // Only IInteger.Add is a candidate ((IDouble)n).Add(1); // Only IDouble.Add is a candidate } }a
n.Add(1)meghívás a túlterhelés feloldási szabályainak alkalmazásával választja ki aIInteger.Adda §12.6.4 szerint. Hasonlóképpen, a hívásn.Add(1.0)kiválasztjaIDouble.Add. Explicit leadások beszúrásakor csak egy jelöltmetódus van, így nincs kétértelműség.záró példa
Példa: Az alábbi kódban
interface IBase { void F(int i); } interface ILeft : IBase { new void F(int i); } interface IRight : IBase { void G(); } interface IDerived : ILeft, IRight {} class A { void Test(IDerived d) { d.F(1); // Invokes ILeft.F ((IBase)d).F(1); // Invokes IBase.F ((ILeft)d).F(1); // Invokes ILeft.F ((IRight)d).F(1); // Invokes IBase.F } }a
IBase.Ftag el van rejtve aILeft.Ftag által. Ad.F(1)hívása ígyILeft.F-t választja, bárIBase.Fúgy tűnik, hogy nincs elrejtve azIRight-en keresztül vezető elérési úton.A többöröklésű felületeken való elrejtés intuitív szabálya egyszerűen a következő: Ha egy tag bármely elérési útvonalon el van rejtve, az minden elérési útvonalon el van rejtve. Mivel a hozzáférési útvonal
IDerivedésILeftközött elrejtiIBase-t, a tag szintén el van rejtve a hozzáférési útvonalbanIBase.FésIDerivedközött.záró példa
19.5 A felület minősített tagnevei
Az illesztőtagot néha minősített illesztőtag néven emlegetik. Az interfész tag minősített neve azon interfész neve, amelyben a tag deklarálva van, ezt egy pont követi, majd a tag neve. A tag minősített neve arra a felületre hivatkozik, amelyben a tag deklarálva van.
Példa: Adott deklarációk esetén
interface IControl { void Paint(); } interface ITextBox : IControl { void SetText(string text); }A(z)
Paintminősített neveIControl.Paint, és a(z) SetText minősített neveITextBox.SetText. A fenti példában nem lehet hivatkozni a következőrePaintITextBox.Paint: .záró példa
Ha egy felület egy névtér része, a minősített illesztőtagok neve magában foglalhatja a névtér nevét.
Példa:
namespace GraphicsLib { interface IPolygon { void CalculateArea(); } }
GraphicsLibnévtéren belül mind aIPolygon.CalculateArea, mind aGraphicsLib.IPolygon.CalculateAreaaCalculateAreametódushoz tartozó interfész tagnevek.záró példa
19.6 Interfész implementációi
19.6.1 Általános
A felületeket osztályok és szerkezetek implementálhatják. Annak jelzéséhez, hogy egy osztály vagy strustruktúra közvetlenül implementál egy interfészt, az interfész szerepel az osztály vagy a szerkezet alaposztálylistájában.
Az interfészt C megvalósító osztálynak vagy szerkezetnek I biztosítania vagy örökölnie kell egy implementációt minden olyan tag I számára, aki C hozzáféréssel rendelkezik. A nyilvános tagok I a következő nyilvános tagokban Chatározhatók meg: Az olyan nem nyilvános tagok, amelyekben I elérhetőek C , explicit felületi megvalósítással C határozhatók meg (19.6.2. §).
Egy származtatott típusú tag, amely megfelel az illesztőleképezésnek (19.6.5. §), de nem implementálja az egyező alapfelület-tagot, új tagot vezet be. Ez akkor fordul elő, ha explicit felületi implementációra van szükség a felület tagjának definiálásához.
Példa:
interface ICloneable { object Clone(); } interface IComparable { int CompareTo(object other); } class ListEntry : ICloneable, IComparable { public object Clone() {...} public int CompareTo(object other) {...} }záró példa
Az interfészt közvetlenül megvalósító osztály vagy struktúra implicit módon implementálja az interfész összes alapillesztőjét is. Ez akkor is igaz, ha az osztály vagy a szerkezet nem sorolja fel explicit módon az alaposztálylistában szereplő összes alapillesztőt.
Példa:
interface IControl { void Paint(); } interface ITextBox : IControl { void SetText(string text); } class TextBox : ITextBox { public void Paint() {...} public void SetText(string text) {...} }Itt a
TextBoxosztály mind aIControl, mind aITextBox-t megvalósítja.záró példa
Amikor egy osztály C közvetlenül implementál egy felületet, az összes származtatott C osztály implicit módon is implementálja az interfészt.
Az osztálydeklarációban megadott alapillesztők felépíthetők illesztőtípusok (8.4. §, 19.2. §).
Példa: Az alábbi kód bemutatja, hogyan valósíthat meg egy osztály létrehozott felülettípusokat:
class C<U, V> {} interface I1<V> {} class D : C<string, int>, I1<string> {} class E<T> : C<int, T>, I1<T> {}záró példa
Az általános osztálybevallás alapfelületeinek meg kell felelniük a 19.6.3.
19.6.2 Explicit felület tag implementációi
Az interfészek megvalósítása céljából az osztály, a szerkezet vagy az interfész explicit felülettag-implementációtdeklarálhat. Az explicit felülettag-implementáció egy metódus, tulajdonság, esemény vagy indexelő deklaráció, amely egy minősített felülettag nevére hivatkozik. A nem nyilvános tagokat az alapillesztőben megvalósító osztálynak vagy szerkezetnek explicit felülettag-implementációt kell deklarálnia. Az alapfelületen tagot implementáló felületnek explicit felülettag-implementációt kell deklarálnia.
A felületleképezésnek megfelelő származtatott illesztőtag (19.6.5. §) elrejti az alap illesztőtagot (7.7.2. §). A fordító figyelmeztetést ad ki, kivéve, ha a new módosító jelen van.
Példa:
interface IList<T> { T[] GetElements(); } interface IDictionary<K, V> { V this[K key] { get; } void Add(K key, V value); } class List<T> : IList<T>, IDictionary<int, T> { public T[] GetElements() {...} T IDictionary<int, T>.this[int index] {...} void IDictionary<int, T>.Add(int index, T value) {...} }Itt található a
IDictionary<int,T>.thisésIDictionary<int,T>.Addexplicit felülettag-implementációk.záró példa
Példa: Bizonyos esetekben előfordulhat, hogy az illesztőtag neve nem felel meg a implementálási osztálynak, ebben az esetben a felülettag explicit felülettag-implementációval implementálható. Egy fájl absztrakciót megvalósító osztály például valószínűleg implementál egy
Closetagfüggvényt, amely felszabadítja a fájlerőforrást, és explicit interfész tagfüggvény implementációval valósítja meg azDisposemetódusát azIDisposableinterfésznek.interface IDisposable { void Dispose(); } class MyFile : IDisposable { void IDisposable.Dispose() => Close(); public void Close() { // Do what's necessary to close the file System.GC.SuppressFinalize(this); } }záró példa
Az explicit felülettag-implementáció nem érhető el a megfelelő illesztőtag nevével egy metódushívásban, tulajdonsághozzáférésben, eseményhozzáférésben vagy indexelő hozzáférésben. Az explicit felületpéldányok tag implementációja csak egy felületpéldányon keresztül érhető el, és ebben az esetben egyszerűen a tag neve hivatkozik rá. Az explicit felület statikus tag-implementációja csak a felület nevével érhető el.
Fordítási idejű hiba, ha egy explicit felülettag implementációja bármilyen módosítót tartalmaz az vagy extern kivételével.
Az explicit interfészmetódus implementációja örökli a típusparaméterek korlátozásait az illesztőtől.
Az explicit interfész metódus implementálása során a type_parameter_constraints_clause csak olyan class vagy structprimary_constraintekből állhat, amelyeket a type_parameterekre alkalmaznak, és amelyek az örökölt kényszerek alapján ismertek, hogy vagy hivatkozási, vagy értéktípusok. Az explicit felületi metódus implementációjának aláírásában szereplő űrlap T? bármely típusa, ahol T típusparaméter van, a következőképpen lesz értelmezve:
- Ha a
classtípusparaméterhezTkényszert ad hozzá, akkorT?null értékű hivatkozástípus; ellenkező esetben - Ha nincs hozzáadott kényszer, vagy egy
structkényszert adnak hozzá, akkor a típusparaméterTegy nullozható értéktípus.
Példa: A következő bemutatja, hogyan működnek a szabályok a típusparaméterek használatakor:
#nullable enable interface I { void Foo<T>(T? value) where T : class; void Foo<T>(T? value) where T : struct; } class C : I { void I.Foo<T>(T? value) where T : class { } void I.Foo<T>(T? value) where T : struct { } }A típusparaméter kényszere
where T : classnélkül a referencia típusú típusparaméterrel rendelkező alapmetódus nem bírálható felül. záró példa
Megjegyzés: Az explicit interfész tagok implementációi más hozzáférhetőségi jellemzőkkel rendelkeznek, mint a többi tag. Mivel az explicit felülettag-implementációk soha nem érhetők el egy metódushívásban vagy tulajdonsághozzáférésben lévő minősített illesztőtagnéven keresztül, bizonyos értelemben privátak. Mivel azonban az interfészen keresztül is elérhetők, olyan értelemben is nyilvánosak, mint az a felület, amelyben deklarálva vannak. Az explicit felülettag-implementációk két elsődleges célt szolgálnak:
- Mivel az explicit illesztőtag-implementációk nem érhetők el osztály- vagy struktúrapéldányokon keresztül, lehetővé teszik, hogy a felületi implementációk ki legyenek zárva egy osztály vagy struktúra nyilvános felületéről. Ez különösen akkor hasznos, ha egy osztály vagy strustruktúra olyan belső felületet implementál, amely nem érdekli az adott osztály vagy szerkezet fogyasztóját.
- Az explicit felülettag-implementációk lehetővé teszik az azonos aláírással rendelkező felülettagok egyértelműsítését. Explicit felülettag-implementációk nélkül lehetetlen lenne, hogy egy osztály, struktúra vagy felület azonos aláírással és visszatérési típussal rendelkezzen az interfésztagok különböző implementációival, ahogyan az osztály, a szerkezet vagy a felület esetében lehetetlen lenne bármilyen implementáció az azonos aláírású, de eltérő visszatérési típusú felülettagok mindegyikén.
végjegyzet
Ahhoz, hogy az explicit felülettag-implementáció érvényes legyen, az osztálynak, a szerkezetnek vagy az interfésznek el kell neveznie egy interfészt az alaposztályában vagy az alapillesztő-listájában, amely egy olyan tagot tartalmaz, akinek a minősített illesztőtag-neve, típusa, típusparamétereinek száma és paramétertípusai pontosan egyeznek az explicit felülettag-implementációéval. Ha egy interfészfüggvény-tag rendelkezik paramétertömbbel, a társított explicit felülettag-implementáció megfelelő paramétere engedélyezett, de nem kötelező, hogy rendelkezzen a params módosítóval. Ha az interfészfüggvény-tag nem rendelkezik paramétertömbbel, akkor a társított explicit illesztőtag-implementáció nem rendelkezik paramétertömbbel.
Példa: Például a következő osztályban
class Shape : ICloneable { object ICloneable.Clone() {...} int IComparable.CompareTo(object other) {...} // invalid }A
IComparable.CompareTodeklarációja fordítási idejű hibát eredményez, mertIComparablenem szerepel aShapealaposztályainak listájában, és nem alapinterfésze aICloneable-nak. Hasonlóképpen, a deklarációkbanclass Shape : ICloneable { object ICloneable.Clone() {...} } class Ellipse : Shape { object ICloneable.Clone() {...} // invalid }
ICloneable.ClonedeklarálásaEllipsefordítási hibát eredményez, mertICloneablenincs kifejezetten felsorolvaEllipsealaposztálylistájában.záró példa
Az explicit interfész tagjának kvalifikált tagneve arra az interfészre hivatkozik, amelyben a tagot deklarálták.
Példa: Így a deklarációkban
interface IControl { void Paint(); } interface ITextBox : IControl { void SetText(string text); } class TextBox : ITextBox { void IControl.Paint() {...} void ITextBox.SetText(string text) {...} }A Paint explicit felülettag-implementációját
IControl.Paintformájában kell írni, nemITextBox.Paint.záró példa
19.6.3 A megvalósított interfészek egyedisége
Az általános típusdeklarációval megvalósított interfészeknek minden lehetséges felépített típus esetében egyedinek kell maradniuk. E szabály nélkül lehetetlen lenne meghatározni a megfelelő metódust bizonyos létrehozott típusok meghívásához.
Példa: Tegyük fel, hogy egy általános osztály deklarációja a következőképpen írható:
interface I<T> { void F(); } class X<U ,V> : I<U>, I<V> // Error: I<U> and I<V> conflict { void I<U>.F() {...} void I<V>.F() {...} }Ha ez engedélyezve lenne, lehetetlen lenne meghatározni, hogy a következő esetben melyik kódot kell végrehajtani:
I<int> x = new X<int, int>(); x.F();záró példa
Annak megállapításához, hogy egy általános típusú deklaráció felületlistája érvényes-e, a következő lépéseket kell végrehajtani:
- Legyen
Laz általános osztályban, szerkezetben vagy interfészdeklarációbanCközvetlenül megadott interfészek listája. - Adja hozzá a
Lelemekhez aLmár meglévő illesztőinek bármely alapillesztőjét. - Távolítsa el az ismétlődéseket a
L-ból. - Ha a típusargumentumok
C-be való behelyettesítése után bármely lehetséges konstruált típus két azonos interfészhez vezetL-ben, akkor aLdeklarációja érvénytelen. A kényszer deklarációk nem tekinthetők meg az összes lehetséges felépített típus meghatározásakor.
Megjegyzés: A fenti osztálydeklarációban
Xa felületlistaLa következőkből álll<U>: ésI<V>. A deklaráció érvénytelen, mert bármely összefércelés, aholUésVugyanaz a típus, ezt a két illesztőfelületet azonos típusokká tenné. végjegyzet
A különböző öröklési szinteken megadott interfészek egyesíthetik az alábbiakat:
interface I<T>
{
void F();
}
class Base<U> : I<U>
{
void I<U>.F() {...}
}
class Derived<U, V> : Base<U>, I<V> // Ok
{
void I<V>.F() {...}
}
Ez a kód akkor is érvényes, ha Derived<U,V> mind I<U>, mind I<V> megvalósít. A kód
I<int> x = new Derived<int, int>();
x.F();
meghívja a metódust Derived, mivel Derived<int,int>' az ténylegesen újra implementálható I<int> (19.6.7. §).
19.6.4 Általános módszerek alkalmazása
Amikor egy általános módszer implicit módon implementál egy interfészmetódust, az egyes metódustípus-paraméterekre vonatkozó korlátozásoknak egyenértékűnek kell lenniük mindkét deklarációban (miután az interfésztípus paramétereit lecserélték a megfelelő típusargumentumokra), ahol a metódustípus paramétereit a balról jobbra lévő sorszámok azonosítják.
Példa: A következő kódban:
interface I<X, Y, Z> { void F<T>(T t) where T : X; void G<T>(T t) where T : Y; void H<T>(T t) where T : Z; } class C : I<object, C, string> { public void F<T>(T t) {...} // Ok public void G<T>(T t) where T : C {...} // Ok public void H<T>(T t) where T : string {...} // Error }a módszer
C.F<T>implicit módon implementálI<object,C,string>.F<T>. Ebben az esetben nincs szükség (és nem is engedélyezett) a korlátozásC.F<T>megadására,T: objectmivelobjectaz minden típusparaméter implicit kényszere. A metódusC.G<T>implicit módon implementálI<object,C,string>.G<T>, mert a kényszerek megegyeznek az illesztőben lévőkkel, miután az illesztőtípus paramétereit lecserélte a megfelelő típusargumentumokra. A metódusC.H<T>kényszere hiba, mert a lezárt típusok (stringebben az esetben) nem használhatók kényszerként. A kényszer kihagyása szintén hiba lenne, mivel az implicit interfészmetódus implementációinak megkötéseinek meg kell egyeznie. Így lehetetlen implicit módon implementálniI<object,C,string>.H<T>. Ez az interfészmetódus csak explicit felülettag-implementációval implementálható:class C : I<object, C, string> { ... public void H<U>(U u) where U : class {...} void I<object, C, string>.H<T>(T t) { string s = t; // Ok H<T>(t); } }Ebben az esetben az explicit felülettag-implementáció egy olyan nyilvános metódust hív meg, amely szigorúan gyengébb korlátozásokkal rendelkezik. A t-ből s-be való hozzárendelés érvényes, mivel
Törökli a kényszertT: string, annak ellenére, hogy ez a kényszer nem fejezhető ki a forráskódban. záró példa
Megjegyzés: Ha egy általános módszer explicit módon implementál egy interfészmetódust, a implementálási módszerre nincs korlátozás (15.7.1. §, 19.6.2. §). végjegyzet
19.6.5 Felületleképezés
Az osztálynak vagy szerkezetnek biztosítania kell az interfészek összes absztrakt tagjának implementálását, amelyek szerepelnek az osztály vagy a szerkezet alaposztálylistájában. Az interfésztagok implementációinak implementálási folyamata egy implementációs osztályban vagy strustruktúra esetében interfészleképezésnek nevezik.
Egy osztály vagy struktúra C interfész-leképezése megkeresi az implementációt az egyes interfészek minden tagjához, amely az alaposztálylistában van megadva C. Egy adott illesztőtag I.Mimplementálását – ahol I a tag M deklarálási felületét is – az egyes osztályok, interfészek vagy szerkezetek Svizsgálatával határozzuk meg, kezdve az egyes egymást követő alaposztályokkal C és annak implementált felületével C, amíg egyezés nem található:
- Ha a
Sdeklarál egy explicit felülettag-implementációt, amely megfelel aIésMtagoknak, akkor ez a tag aI.Mimplementációja. - Ellenkező esetben, ha a
Segy nem statikus nyilvános tag számára tartalmaz deklarációt, amely megfelel aM-nek, akkor ez a tag aI.Mmegvalósítása. Ha egynél több tag egyezik, nincs meghatározva, hogy melyik tag az implementációjaI.M. Ez a helyzet csak akkor fordulhat elő, haSegy olyan létrehozott típus, amelyben az általános típusban deklarált két tag eltérő aláírással rendelkezik, de a típusargumentumok azonosvá teszik az aláírásukat.
Fordítási időhiba lép fel, ha a implementációk nem találhatók a rendszer alaposztálylistájában megadott összes felület minden tagjára Cvonatkozóan. Az interfész tagjai közé tartoznak azok a tagok, amelyek az alapinterfészekből öröklődnek.
A létrehozott interfésztípus tagjait úgy tekintjük, hogy az egyes típusparamétereket az §15.3.3-ben megadott megfelelő típusargumentumokkal helyettesítik.
Példa: Például az általános felületi deklaráció miatt:
interface I<T> { T F(int x, T[,] y); T this[int y] { get; } }a létrehozott felület
I<string[]>tagjai:string[] F(int x, string[,][] y); string[] this[int y] { get; }záró példa
Felületleképezés céljából egy osztály, interfész vagy strucctag A akkor egyezik meg egy felülettagval B , ha:
-
AésBmetódusok, ésAésBneve, típusa és paraméterlistája azonos. -
AésBtulajdonságok, a név és a típusA, ésBazonosak, ésAugyanazokkal a tartozékokkal rendelkezik, mintB(Amegengedett, hogy további tartozékokkal rendelkezzen, ha nem explicit felületi tag implementáció). -
AésBesemények, és aAésBneve és típusa azonos. -
AésBindexelők, aAésBtípus- és paraméterlistái azonosak, ésAugyanazokkal a hozzáférési metódusokkal rendelkezik, mintB(Atovábbi hozzáférési metódusokkal is rendelkezhet, ha nem explicit interfész-tag implementáció).
Az interfész-leképezési algoritmus jelentős következményei a következők:
- Az explicit felülettag-implementációk elsőbbséget élveznek az ugyanabban az osztályban vagy szerkezetben lévő többi taggal szemben az illesztőtagot megvalósító osztály vagy tagstruktúra meghatározásakor.
- Sem a nem nyilvános, sem a statikus tagok nem vesznek részt a felületleképezésben.
Példa: Az alábbi kódban
interface ICloneable { object Clone(); } class C : ICloneable { object ICloneable.Clone() {...} public object Clone() {...} }A(z)
ICloneable.Clonetagja a(z)C-ban a(z)Clonemegvalósításává válik a(z)ICloneable-ban, mivel az explicit felülettag-implementációk elsőbbséget élveznek más tagokkal szemben.záró példa
Ha egy osztály vagy szerkezet két vagy több olyan illesztőt implementál, amely azonos nevű, típusú és paramétertípusú tagot tartalmaz, az illesztőtagok mindegyike megfeleltethető egyetlen osztályra vagy strukturált tagra.
Példa:
interface IControl { void Paint(); } interface IForm { void Paint(); } class Page : IControl, IForm { public void Paint() {...} }Itt mind a
Paint, mind aIControlmódszerei aIFormmetódushoz lettek megfeleltetve aPaint-ben. Természetesen külön explicit felülettag-implementációk is lehetségesek a két módszerhez.záró példa
Ha egy osztály vagy strustruktúra rejtett tagokat tartalmazó felületet implementál, akkor előfordulhat, hogy egyes tagokat explicit felületi tag-implementációkkal kell implementálni.
Példa:
interface IBase { int P { get; } } interface IDerived : IBase { new int P(); }Ennek az interfésznek a megvalósítása legalább egy explicit felületi tag implementálását igényelné, és az alábbi űrlapok egyikét venné igénybe
class C1 : IDerived { int IBase.P { get; } int IDerived.P() {...} } class C2 : IDerived { public int P { get; } int IDerived.P() {...} } class C3 : IDerived { int IBase.P { get; } public int P() {...} }záró példa
Ha egy osztály több, azonos alapfelülettel rendelkező adaptert implementál, az alapillesztőnek csak egy implementációja lehet.
Példa: Az alábbi kódban
interface IControl { void Paint(); } interface ITextBox : IControl { void SetText(string text); } interface IListBox : IControl { void SetItems(string[] items); } class ComboBox : IControl, ITextBox, IListBox { void IControl.Paint() {...} void ITextBox.SetText(string text) {...} void IListBox.SetItems(string[] items) {...} }nem lehet külön implementációkat létrehozni az
IControlalaposztálylistában szereplő névhez, azIControláltal örököltITextBox, és azIControláltal örököltIListBox. Ezen interfészek esetében nincs külön identitás fogalma. Ehelyett aITextBoxés aIListBoxugyanazt aIControlimplementációt osztja meg, és aComboBoxegyszerűen úgy tekinthető, mint amely három interfészt valósít meg:IControl,ITextBox, ésIListBox.záró példa
Az alaposztály tagjai részt vesznek a felületleképezésben.
Példa: Az alábbi kódban
interface Interface1 { void F(); } class Class1 { public void F() {} public void G() {} } class Class2 : Class1, Interface1 { public new void G() {} }A
Fmódszert aClass1aClass2'srendszer implementációjában használjákInterface1.záró példa
19.6.6 Interfész implementálásának öröklése
Az osztály örökli az alaposztályai által biztosított összes felületi implementációt.
Az interfész explicit újra implementálása nélkül a származtatott osztály semmilyen módon nem módosíthatja az alaposztályoktól örökölt interfész-leképezéseket.
Példa: A deklarációkban
interface IControl { void Paint(); } class Control : IControl { public void Paint() {...} } class TextBox : Control { public new void Paint() {...} }a
Paintmetódus aTextBox-ban elrejti aPaintmetódust aControl-ban, de nem módosítja aControl.Paintleképezését azIControl.Paint-re, és az osztálypéldányokon és felületpéldányokon keresztüliPainthívások a következő hatásokkal járnakControl c = new Control(); TextBox t = new TextBox(); IControl ic = c; IControl it = t; c.Paint(); // invokes Control.Paint(); t.Paint(); // invokes TextBox.Paint(); ic.Paint(); // invokes Control.Paint(); it.Paint(); // invokes Control.Paint();záró példa
Ha azonban egy interfészmetódus egy osztály virtuális metódusára van leképezve, lehetséges, hogy a származtatott osztályok felülbírálják a virtuális metódust, és módosítják a felület implementációját.
Példa: A fenti deklarációk újraírása a következőre:
interface IControl { void Paint(); } class Control : IControl { public virtual void Paint() {...} } class TextBox : Control { public override void Paint() {...} }a következő hatások figyelhetők meg
Control c = new Control(); TextBox t = new TextBox(); IControl ic = c; IControl it = t; c.Paint(); // invokes Control.Paint(); t.Paint(); // invokes TextBox.Paint(); ic.Paint(); // invokes Control.Paint(); it.Paint(); // invokes TextBox.Paint();záró példa
Mivel az explicit felülettag-implementációk nem deklarálhatók virtuálisan, nem lehet felülbírálni egy explicit felülettag-implementációt. Az explicit felülettag implementációja azonban teljesen érvényes arra, hogy meghívjon egy másik metódust, és ezt a másik metódust lehet virtuálisan deklarálni, hogy a származtatott osztályok felüldefiniálhassák azt.
Példa:
interface IControl { void Paint(); } class Control : IControl { void IControl.Paint() { PaintControl(); } protected virtual void PaintControl() {...} } class TextBox : Control { protected override void PaintControl() {...} }Itt a
Controlosztályokból származtatott osztályok aIControl.Paintmetódus felülbírálásával specializálhatják aPaintControlvégrehajtását.záró példa
19.6.7 Interfész újra implementálása
Az interfész implementálását öröklő osztály újra implementálhatja a felületet úgy, hogy felveszi az alaposztálylistába.
Az interfészek újra implementálása pontosan ugyanazokat a felületleképezési szabályokat követi, mint egy felület kezdeti implementációja. Így az örökölt felületleképezés semmilyen hatással nincs a felület újra implementálására létrehozott felületleképezésre.
Példa: A deklarációkban
interface IControl { void Paint(); } class Control : IControl { void IControl.Paint() {...} } class MyControl : Control, IControl { public void Paint() {} }az a tény, hogy
Control-tIControl.Paint-re leképeziControl.IControl.Paint-t, nem befolyásoljaMyControlújramegvalósítását, amiIControl.Paint-tMyControl.Paint-re leképez.záró példa
Az örökölt nyilvános tag-deklarációk és az örökölt explicit felülettag-deklarációk részt vesznek az újra implementált felületek felületleképezési folyamatában.
Példa:
interface IMethods { void F(); void G(); void H(); void I(); } class Base : IMethods { void IMethods.F() {} void IMethods.G() {} public void H() {} public void I() {} } class Derived : Base, IMethods { public void F() {} void IMethods.H() {} }Itt az implementáció leképezi az interfész metódusait
IMethodsDerivedazDerived.F,Base.IMethods.G,Derived.IMethods.HésBase.Ielemekre.záró példa
Amikor egy osztály implementál egy interfészt, implicit módon az interfész összes alapfelületét is implementálja. Hasonlóképpen, az interfész újra implementálása implicit módon az interfész összes alapfelületének újra implementálása is.
Példa:
interface IBase { void F(); } interface IDerived : IBase { void G(); } class C : IDerived { void IBase.F() {...} void IDerived.G() {...} } class D : C, IDerived { public void F() {...} public void G() {...} }Itt a
IDerivedújraimplementálása is újraimplementálja aIBase-t, hozzárendelve aIBase.F-t aD.F-hoz.záró példa
19.6.8 Absztrakt osztályok és felületek
A nem absztrakt osztályhoz hasonlóan az absztrakt osztálynak is biztosítania kell az osztály alaposztálylistájában felsorolt interfészek összes absztrakt tagjának implementálását. Az absztrakt osztályok azonban interfész metódusokat képezhetnek le absztrakt metódusokra.
Példa:
interface IMethods { void F(); void G(); } abstract class C : IMethods { public abstract void F(); public abstract void G(); }Itt a
IMethodsmegvalósítása aFésGelemeket absztrakt metódusokra képezi le, amelyeket felül kell bírálni azokban a nem absztrakt osztályokban, amelyek aC-ből származnak.záró példa
Az explicit felülettag-implementációk nem lehetnek absztraktak, de az explicit felülettag-implementációk természetesen absztrakt metódusokat is meghívhatnak.
Példa:
interface IMethods { void F(); void G(); } abstract class C: IMethods { void IMethods.F() { FF(); } void IMethods.G() { GG(); } protected abstract void FF(); protected abstract void GG(); }Itt a
C-ből származó nem absztrakt osztályoknak felül kell bírálniuk aFF-t és aGG-t, így biztosítva ezzel aIMethodstényleges megvalósítását.záró példa
ECMA C# draft specification