Nyelvi függetlenség és nyelvfüggetlen összetevők
A .NET nyelvfüggetlen. Ez azt jelenti, hogy fejlesztőként a .NET-implementációkat ( például C#, F# és Visual Basic) célzó nyelvek egyikében fejleszthet. A .NET-implementációkhoz kifejlesztett osztálykódtárak típusait és tagjait anélkül érheti el, hogy ismernie kellene az eredeti nyelv nyelvét, és nem kell követnie az eredeti nyelv konvencióit. Ha Ön összetevő-fejlesztő, az összetevő a nyelvétől függetlenül bármely .NET-alkalmazással elérhető.
Feljegyzés
A cikk első része a nyelvfüggetlen összetevők létrehozását ismerteti, vagyis azokat az összetevőket, amelyeket bármilyen nyelven írt alkalmazások használhatnak. Egyetlen összetevőt vagy alkalmazást több nyelven írt forráskódból is létrehozhat; lásd a cikk második részében a nyelvek közötti együttműködésről szóló cikket.
A bármilyen nyelven írt más objektumokkal való teljes interakcióhoz az objektumoknak csak azokat a szolgáltatásokat kell elérhetővé tenni a hívók számára, amelyek minden nyelvre jellemzőek. Ezt a közös funkciókészletet a Common Language Specification (CLS) határozza meg, amely a létrehozott szerelvényekre vonatkozó szabályok halmaza. A közös nyelvi specifikációt az ECMA-335 Szabvány 7–11. záradéka, a Common Language Infrastructure I. partíciója határozza meg.
Ha az összetevő megfelel a Common Language Specification szabványnak, garantáltan CLS-kompatibilis lesz, és bármely olyan programozási nyelven írt kódból elérhető, amely támogatja a CLS-t. A CLSCompliantAttribute attribútum forráskódra való alkalmazásával megállapíthatja, hogy az összetevő megfelel-e a Common Language Specification szabványnak fordításkor. További információ: A CLSCompliantAttribute attribútum.
CLS-megfelelőségi szabályok
Ez a szakasz a CLS-kompatibilis összetevők létrehozásának szabályait ismerteti. A szabályok teljes listáját az ECMA-335 Standard: Common Language Infrastructure I. partíciója, 11. záradéka tartalmazza.
Feljegyzés
A Common Language Specification a CLS-megfelelőség minden szabályát ismerteti, mivel az a felhasználókra (a CLS-kompatibilis összetevőket programozott módon elérő fejlesztőkre), a keretrendszerekre (a CLS-kompatibilis kódtárak létrehozására nyelvfordítót használó fejlesztőkre) és a bővítőkre (olyan fejlesztőkre vonatkozik, akik olyan eszközt hoznak létre, mint például egy nyelvfordító vagy egy CLS-kompatibilis összetevőket létrehozó kódelemző). Ez a cikk a keretrendszerekre vonatkozó szabályokat ismerteti. Vegye figyelembe azonban, hogy a hosszabbítókra vonatkozó szabályok némelyike az Önkifejezés ion használatával létrehozott szerelvényekre is vonatkozhat. Kibocsát.
A nyelvfüggetlen összetevők tervezéséhez csak a CLS-megfelelőségre vonatkozó szabályokat kell alkalmaznia az összetevő nyilvános felületére. A privát implementációnak nem kell megfelelnie a specifikációnak.
Fontos
A CLS-megfelelőségre vonatkozó szabályok csak az összetevők nyilvános felületére vonatkoznak, a privát megvalósításra nem.
Például a nem aláírt egész számok Byte nem CLS-kompatibilisek. Mivel a Person
következő példában szereplő osztály egy Age
típustulajdonságot UInt16tesz elérhetővé, az alábbi kód egy fordító figyelmeztetést jelenít meg.
using System;
[assembly: CLSCompliant(true)]
public class Person
{
private UInt16 personAge = 0;
public UInt16 Age
{ get { return personAge; } }
}
// The attempt to compile the example displays the following compiler warning:
// Public1.cs(10,18): warning CS3003: Type of 'Person.Age' is not CLS-compliant
<Assembly: CLSCompliant(True)>
Public Class Person
Private personAge As UInt16
Public ReadOnly Property Age As UInt16
Get
Return personAge
End Get
End Property
End Class
' The attempt to compile the example displays the following compiler warning:
' Public1.vb(9) : warning BC40027: Return type of function 'Age' is not CLS-compliant.
'
' Public ReadOnly Property Age As UInt16
' ~~~
A CLS osztályt úgy teheti megfelelővéPerson
, hogy Int16a tulajdonság UInt16 típusát Age
egy CLS-kompatibilis, 16 bites aláírt egész számra módosítja. A privát personAge
mező típusát nem kell módosítania.
using System;
[assembly: CLSCompliant(true)]
public class Person
{
private Int16 personAge = 0;
public Int16 Age
{ get { return personAge; } }
}
<Assembly: CLSCompliant(True)>
Public Class Person
Private personAge As UInt16
Public ReadOnly Property Age As Int16
Get
Return CType(personAge, Int16)
End Get
End Property
End Class
A tár nyilvános felülete a következőkből áll:
A nyilvános osztályok definíciói.
A nyilvános osztályok nyilvános tagjainak definíciói és a származtatott osztályokhoz (azaz védett tagokhoz) elérhető tagok definíciói.
A nyilvános osztályok nyilvános metódusainak paraméterei és visszatérési típusai, valamint a származtatott osztályok számára elérhető metódusok paraméterei és visszatérési típusai.
A CLS-megfelelőségre vonatkozó szabályok az alábbi táblázatban találhatók. A szabályok szövege szó szerint az ECMA-335 Standard: Common Language Infrastructure, azaz az Ecma International Copyright 2012 szabványából származik. Ezekről a szabályokról a következő szakaszokban talál részletesebb információkat.
Kategória | Lásd: | Szabály | Szabályszám |
---|---|---|---|
Akadálymentesség | A tagok akadálymentessége | Az öröklött metódusok felülírásakor az akadálymentesség nem módosítható, kivéve, ha egy másik, akadálymentes family-or-assembly szerelvénytől örökölt metódust felül kell bírálni. Ebben az esetben a felülbírálásnak akadálymentesnek family kell minősülnie. |
10 |
Akadálymentesség | A tagok akadálymentessége | A típusok és tagok láthatóságának és hozzáférhetőségének olyannak kell lennie, hogy bármely tag aláírásában szereplő típusok láthatóak és hozzáférhetőek legyenek, amikor maga a tag látható és hozzáférhető. Például egy nyilvános módszernek, amely a szerelvényen kívül látható, nem lehet olyan argumentuma, amelynek típusa csak a szerelvényen belül látható. Minden tag aláírásában használt példányosított általános típust alkotó típusok láthatósága és akadálymentessége látható és hozzáférhető, ha maga a tag látható és hozzáférhető. Egy olyan példányosított általános típus például, amely a szerelvényen kívül látható tag aláírásában található, nem tartalmazhat olyan általános argumentumot, amelynek típusa csak a szerelvényen belül látható. | 12 |
Tömbök | Tömbök | A tömböknek CLS-kompatibilis típusú elemeket kell tartalmazniuk, és a tömb minden dimenziójának nulla alsó határral kell rendelkeznie. A túlterhelések megkülönböztetéséhez csak azt a tényt kell megkülönböztetni, hogy egy elem tömb és a tömb elemtípusa. Ha a túlterhelés két vagy több tömbtípuson alapul, az elemtípusokat el kell nevezni. | 16 |
Attribútumok | Attribútumok | Az attribútumoknak típusuknak System.Attributevagy azoktól öröklő típusnak kell lenniük. | 41 |
Attribútumok | Attribútumok | A CLS csak az egyéni attribútumok kódolásának egy részét teszi lehetővé. Ezekben a kódolásokban csak a következő típusok jelennek meg: (lásd: IV. partíció): System.Type, System.String, System.Char, System.Boolean, System.Int32System.ByteSystem.Int64System.Int16, System.Single, , System.Doubleés bármilyen, CLS-kompatibilis alap egész számtípuson alapuló enumerálási típus. | 34 |
Attribútumok | Attribútumok | A CLS nem teszi lehetővé a nyilvánosan látható kötelező módosítókat (modreq lásd a Partíció II-t), de engedélyezi az opcionális módosítókat (modopt lásd a Partíció II-t), amelyeket nem ért meg. |
35 |
Konstruktorok | Konstruktorok | Az objektumkonstruktornak meg kell hívnia az alaposztály egyes példánykonstruktorait, mielőtt bármilyen hozzáférés történne az örökölt példányadatokhoz. (Ez nem vonatkozik azokra az értéktípusokra, amelyeknek nem kell konstruktorokkal rendelkezniük.) | 21 |
Konstruktorok | Konstruktorok | Az objektumkonstruktor csak az objektum létrehozásának részeként hívható meg, és az objektum nem inicializálható kétszer. | 22 |
Enumerálások | Számbavételek | Az enumerálás alapjául szolgáló típus egy beépített CLS egész számtípus, a mező neve "value__", és ezt a mezőt meg kell jelölni RTSpecialName . |
7 |
Enumerálások | Számbavételek | Két különböző típusú enumerálás létezik, amelyeket az egyéni attribútum jelenléte vagy hiánya jelez (lásd: System.FlagsAttribute Partition IV Library). Az egyik nevesített egész számértékeket jelöl; a másik az elnevezett bitjelzőket jelöli, amelyek egy névtelen érték létrehozásához kombinálhatók. Egy érték enum nem korlátozódik a megadott értékekre. |
8 |
Enumerálások | Számbavételek | A szám konstans statikus mezőinek magának az enumnak a típusával kell rendelkezniük. | 9 |
esemény | Események | Az eseményt megvalósító módszereket a metaadatokban kell megjelölni SpecialName . |
29 |
esemény | Események | Az esemény és tartozékai akadálymentessége azonos. | 30 |
esemény | Események | Az add esemény és remove az esemény módszereinek egyaránt jelen kell lenniük, vagy hiányoznak. |
31 |
esemény | Események | Az add esemény és remove az esemény módszerei mind egy olyan paramétert vesznek fel, amelynek típusa meghatározza az esemény típusát, és amelyet a System.Delegáltból kell származtatni. |
32 |
esemény | Események | Az eseményeknek meg kell felelnie egy adott elnevezési mintának. A 29. CLS-szabályban említett SpecialName attribútumot figyelmen kívül kell hagyni a megfelelő név-összehasonlításokban, és be kell tartani az azonosító szabályokat. | 33 |
Kivételek | Kivételek | A kidobott objektumoknak System.Exception típusúnak vagy attól öröklő típusnak kell lenniük . Ennek ellenére a CLS-kompatibilis módszerek nem szükségesek más típusú kivételek propagálásának letiltásához. | 40 |
Általános | CLS-megfelelőségi szabályok | A CLS-szabályok csak a típus azon részeire vonatkoznak, amelyek a meghatározó szerelvényen kívül érhetők el vagy láthatók. | 0 |
Általános | CLS-megfelelőségi szabályok | A nem CLS-kompatibilis típusok tagjai nem jelölhetők CLS-kompatibilisnek. | 2 |
Generikus | Általános típusok és tagok | A beágyazott típusoknak legalább annyi általános paramétert kell tartalmazniuk, mint a beágyazási típusnak. A beágyazott típus általános paraméterei a beágyazási típus általános paramétereinek pozíciója szerint felelnek meg. | 42 |
Generikus | Általános típusok és tagok | Az általános típus neve kódolja a nem beágyazott típuson deklarált vagy beágyazott típusba újonnan bevezetett típusparaméterek számát a fent meghatározott szabályok szerint. | 43 |
Generikus | Általános típusok és tagok | Az általános típusnak elegendő korlátozást kell újból megállapítania annak biztosítására, hogy az alaptípusra vagy interfészekre vonatkozó korlátozások teljesüljenek az általános típusmegkötésekkel. | 44 |
Generikus | Általános típusok és tagok | Az általános paraméterek korlátozásaként használt típusoknak maguknak CLS-kompatibilisnek kell lenniük. | 45 |
Generikus | Általános típusok és tagok | A példányosított általános típusban lévő tagok (beleértve a beágyazott típusokat is) láthatóságát és akadálymentességét az általános típusdeklaráció egésze helyett az adott példányra kell kiterjedni. Feltételezve, hogy a 12. CLS-szabály láthatósági és akadálymentességi szabályai továbbra is érvényesek. | 46 |
Generikus | Általános típusok és tagok | Minden egyes absztrakt vagy virtuális általános módszer esetében alapértelmezett konkrét (nem abstract) implementációt kell alkalmazni | 47 |
Interfészek | Felületek | A CLS-kompatibilis interfészek nem követelik meg a nem CLS-kompatibilis módszerek meghatározását az implementálásukhoz. | 18 |
Interfészek | Felületek | A CLS-kompatibilis interfészek nem határozhatnak meg statikus módszereket, és nem határozhatnak meg mezőket. | 19 |
Tagok | Általában írja be a tagokat | A globális statikus mezők és metódusok nem cls-kompatibilisek. | 36 |
Tagok | -- | A konstans statikus értékének megadása mező inicializálási metaadatokkal történik. A CLS-kompatibilis literálnak a mező inicializálási metaadataiban megadott értékkel kell rendelkeznie, amely pontosan megegyezik a literál típusával (vagy az alapul szolgáló típussal, ha ez a literál egy enum ). |
13 |
Tagok | Általában írja be a tagokat | A vararg-korlátozás nem része a CLS-nek, és a CLS által támogatott egyetlen hívási konvenció a szabványos felügyelt hívási konvenció. | 15 |
Elnevezési konvenciók | Elnevezési konvenciók | A szerelvények a Unicode Standard3.0 15. technikai jelentésének 7. mellékletét követik, amely szabályozza azoknak a karaktereknek a készletét, amelyek az unicode normalizálási űrlapokon online elérhetők, és amelyek az azonosítókban engedélyezettek és szerepelhetnek az azonosítókban. Az azonosítóknak a Unicode Normalization Form C által meghatározott canonical formátumban kell lenniük. CLS-célokra két azonosító azonos, ha a kisbetűs leképezéseik (a Unicode területileg nem érzéketlen, az egy-az-egyhez kisbetűs leképezések) megegyeznek. Vagyis ahhoz, hogy két azonosítót eltérőnek lehessen tekinteni a CLS-ben, azoknak többben kell különbözniük, mint egyszerűen az esetükben. Az örökölt definíciók felülbírálásához azonban a cli megköveteli az eredeti deklaráció pontos kódolását. | 4 |
Túlterhelés | Elnevezési konvenciók | A CLS-kompatibilis hatókörben bevezetett neveknek különbözőnek kell lenniük egymástól függetlenül, kivéve, ha a nevek azonosak, és túlterheléssel oldódnak fel. Ez azt jelenti, hogy míg a CTS lehetővé teszi, hogy egyetlen típus ugyanazt a nevet használja egy metódushoz és egy mezőhöz, a CLS nem. | 5 |
Túlterhelés | Elnevezési konvenciók | A mezőknek és a beágyazott típusoknak egyedinek kell lenniük az azonosítók összehasonlításával, annak ellenére, hogy a CTS lehetővé teszi a különböző aláírások megkülönböztetésére. Az azonos nevű metódusoknak, tulajdonságoknak és eseményeknek (azonosító-összehasonlítás alapján) a visszatérési típusnál többel kell eltérnie, kivéve a 39. CLS-szabályban meghatározottakat | 6 |
Túlterhelés | Túlterhelés | Csak tulajdonságok és metódusok terhelhetők túl. | 37 |
Túlterhelés | Túlterhelés | A tulajdonságok és metódusok csak a paraméterek száma és típusai alapján terhelhetők túl, kivéve a névvel ellátott op_Implicit op_Explicit konverziós operátorokat, és amelyek a visszatérési típusuk alapján is túlterhelhetők. |
38 |
Túlterhelés | -- | Ha egy típusban deklarált két vagy több CLS-kompatibilis metódusnak ugyanaz a neve, és adott típus-példányok esetében ugyanazzal a paraméterrel és visszatérési típussal rendelkeznek, akkor ezeknek a módszereknek szemantikailag egyenértékűnek kell lenniük az ilyen típusú példányok esetében. | 48 |
Tulajdonságok | Tulajdonságok | A tulajdonságok lekérési és beállítási módszereit megvalósító módszereket a metaadatokban kell megjelölni SpecialName . |
24 |
Tulajdonságok | Tulajdonságok | A tulajdonság tartozékainak statikusnak, virtuálisnak vagy példánynak kell lenniük. | 26 |
Tulajdonságok | Tulajdonságok | A tulajdonság típusa a getter visszatérési típusa és a beállító utolsó argumentumának típusa. A tulajdonság paramétereinek típusai a getterhez tartozó paraméterek típusai, valamint a beállító végső paramétere kivételével az összes típusának kell lenniük. E típusok mindegyikének CLS-kompatibilisnek kell lennie, és nem kezelhetők (azaz referencia alapján nem adható át). | 27 |
Tulajdonságok | Tulajdonságok | A tulajdonságoknak meg kell felelnie egy adott elnevezési mintának. A SpecialName 24. CLS-szabályban említett attribútumot a megfelelő név-összehasonlításokban figyelmen kívül kell hagyni, és be kell tartani az azonosító szabályokat. A tulajdonságnak gettermetódussal, halmazmetódussal vagy mindkettővel kell rendelkeznie. |
28 |
Típuskonverzió | Típuskonvertálás | Ha op_Implicit vagy op_Explicit van megadva, alternatív módot kell biztosítani a kényszerítés biztosítására. | 39 |
Típusok | Típusok és típustag-aláírások | A dobozos értéktípusok nem CLS-kompatibilisek. | 3 |
Típusok | Típusok és típustag-aláírások | Az aláírásban megjelenő összes típusnak CLS-kompatibilisnek kell lennie. A példányosított általános típust alkotó összes típusnak CLS-kompatibilisnek kell lennie. | 11 |
Típusok | Típusok és típustag-aláírások | A beírt hivatkozások nem CLS-kompatibilisek. | 14 |
Típusok | Típusok és típustag-aláírások | A nem felügyelt mutatótípusok nem CLS-kompatibilisek. | 17 |
Típusok | Típusok és típustag-aláírások | A CLS-kompatibilis osztályok, értéktípusok és interfészek nem követelik meg a nem CLS-kompatibilis tagok végrehajtását | 20 |
Típusok | Típusok és típustag-aláírások | A System.Object CLS-kompatibilis. Bármely más CLS-kompatibilis osztály örököl egy CLS-kompatibilis osztályt. | 23 |
Alszakaszok indexe:
- Típusok és típustag-aláírások
- Elnevezési konvenciók
- Típuskonvertálás
- Tömbök
- Felületek
- Számbavételek
- Általában írja be a tagokat
- A tagok akadálymentessége
- Általános típusok és tagok
- Konstruktorok
- Tulajdonságok
- Események
- Túlterhelés
- Kivételek
- Attribútumok
Típusok és típustag-aláírások
A System.Object típus CLS-kompatibilis, és a .NET típusú rendszer összes objektumtípusának alaptípusa. A .NET-ben az öröklés implicit (például a Sztring osztály implicit módon örököl az Object
osztálytól) vagy explicit (például a CultureNotFoundException osztály explicit módon örökli az ArgumentException osztályt, amely explicit módon örökli a Kivétel osztályt. Ahhoz, hogy egy származtatott típus CLS-kompatibilis legyen, az alaptípusnak CLS-kompatibilisnek is kell lennie.
Az alábbi példa egy olyan származtatott típust mutat be, amelynek alaptípusa nem CLS-kompatibilis. Egy alaposztályt Counter
határoz meg, amely egy nem aláírt 32 bites egész számot használ számlálóként. Mivel az osztály számlálófunkciót biztosít egy aláíratlan egész szám körbefuttatásával, az osztály nem CLS-kompatibilisként van megjelölve. Ennek eredményeképpen a származtatott osztály szintén NonZeroCounter
nem CLS-kompatibilis.
using System;
[assembly: CLSCompliant(true)]
[CLSCompliant(false)]
public class Counter
{
UInt32 ctr;
public Counter()
{
ctr = 0;
}
protected Counter(UInt32 ctr)
{
this.ctr = ctr;
}
public override string ToString()
{
return String.Format("{0}). ", ctr);
}
public UInt32 Value
{
get { return ctr; }
}
public void Increment()
{
ctr += (uint) 1;
}
}
public class NonZeroCounter : Counter
{
public NonZeroCounter(int startIndex) : this((uint) startIndex)
{
}
private NonZeroCounter(UInt32 startIndex) : base(startIndex)
{
}
}
// Compilation produces a compiler warning like the following:
// Type3.cs(37,14): warning CS3009: 'NonZeroCounter': base type 'Counter' is not
// CLS-compliant
// Type3.cs(7,14): (Location of symbol related to previous warning)
<Assembly: CLSCompliant(True)>
<CLSCompliant(False)> _
Public Class Counter
Dim ctr As UInt32
Public Sub New
ctr = 0
End Sub
Protected Sub New(ctr As UInt32)
ctr = ctr
End Sub
Public Overrides Function ToString() As String
Return String.Format("{0}). ", ctr)
End Function
Public ReadOnly Property Value As UInt32
Get
Return ctr
End Get
End Property
Public Sub Increment()
ctr += CType(1, UInt32)
End Sub
End Class
Public Class NonZeroCounter : Inherits Counter
Public Sub New(startIndex As Integer)
MyClass.New(CType(startIndex, UInt32))
End Sub
Private Sub New(startIndex As UInt32)
MyBase.New(CType(startIndex, UInt32))
End Sub
End Class
' Compilation produces a compiler warning like the following:
' Type3.vb(34) : warning BC40026: 'NonZeroCounter' is not CLS-compliant
' because it derives from 'Counter', which is not CLS-compliant.
'
' Public Class NonZeroCounter : Inherits Counter
' ~~~~~~~~~~~~~~
A tagajánlásokban megjelenő összes típusnak, beleértve a metódus visszatérési típusát vagy tulajdonságtípusát, CLS-kompatibilisnek kell lennie. Emellett általános típusok esetén:
A példányosított általános típust alkotó összes típusnak CLS-kompatibilisnek kell lennie.
Az általános paraméterek korlátozásaként használt összes típusnak CLS-kompatibilisnek kell lennie.
A .NET közös típusrendszer számos beépített típust tartalmaz, amelyeket közvetlenül a közös nyelvi futtatókörnyezet támogat, és amelyeket kifejezetten egy szerelvény metaadataiban kódolnak. Ezen belső típusok közül az alábbi táblázatban felsorolt típusok CLS-kompatibilisek.
CLS-kompatibilis típus | Leírás |
---|---|
Bájt | 8 bites aláíratlan egész szám |
Int16 | 16 bites aláírt egész szám |
Int32 | 32 bites aláírt egész szám |
Int64 | 64 bites aláírt egész szám |
Fele | Fél pontosságú lebegőpontos érték |
Egyetlen | Egypontos lebegőpontos érték |
Dupla | Dupla pontosságú lebegőpontos érték |
Logikai | igaz vagy hamis értéktípus |
Char | UTF-16 kódolt kódegység |
Decimális | Nem lebegőpontos decimális szám |
IntPtr | Platform által definiált méret mutatója vagy fogópontja |
Sztring | Nulla, egy vagy több Karakterobjektum gyűjteménye |
Az alábbi táblázatban felsorolt belső típusok nem CLS-kompatibilisek.
Nem megfelelő típus | Leírás | CLS-kompatibilis alternatíva |
---|---|---|
SByte | 8 bites aláírt egész szám adattípusa | Int16 |
UInt16 | 16 bites aláíratlan egész szám | Int32 |
UInt32 | 32 bites aláíratlan egész szám | Int64 |
UInt64 | 64 bites aláíratlan egész szám | Int64 (túlcsordulás), BigInteger vagy Double |
UIntPtr | Aláíratlan mutató vagy fogópont | IntPtr |
A .NET-osztálytár vagy bármely más osztálytár tartalmazhat más, nem CLS-kompatibilis típusokat, például:
Dobozos értéktípusok. Az alábbi C#-példa létrehoz egy osztályt, amelynek neve nyilvános tulajdonságú
int*
Value
. Mivel egyint*
dobozos értéktípus, a fordító nem CLS-kompatibilisként jelöli meg.using System; [assembly:CLSCompliant(true)] public unsafe class TestClass { private int* val; public TestClass(int number) { val = (int*) number; } public int* Value { get { return val; } } } // The compiler generates the following output when compiling this example: // warning CS3003: Type of 'TestClass.Value' is not CLS-compliant
Gépelt hivatkozások, amelyek olyan speciális szerkezetek, amelyek egy objektumra mutató hivatkozást és egy típusra mutató hivatkozást tartalmaznak. A beírt hivatkozásokat az TypedReference osztály a .NET-ben jelöli.
Ha egy típus nem CLS-kompatibilis, akkor az CLSCompliantAttribute attribútumot annak értékével isCompliant
kell alkalmaznia false
. További információ: A CLSCompliantAttribute attribútum szakasz.
Az alábbi példa a CLS-megfelelőség problémáját mutatja be egy metódus-aláírásban és az általános típusú példányosításban. Meghatároz egy osztályt InvoiceItem
egy típustulajdonságú UInt32, egy típustulajdonságú Nullable<UInt32>
és egy típusparamétert UInt32 tartalmazó Nullable<UInt32>
konstruktort. A példa lefordításakor négy fordítói figyelmeztetés jelenik meg.
using System;
[assembly: CLSCompliant(true)]
public class InvoiceItem
{
private uint invId = 0;
private uint itemId = 0;
private Nullable<uint> qty;
public InvoiceItem(uint sku, Nullable<uint> quantity)
{
itemId = sku;
qty = quantity;
}
public Nullable<uint> Quantity
{
get { return qty; }
set { qty = value; }
}
public uint InvoiceId
{
get { return invId; }
set { invId = value; }
}
}
// The attempt to compile the example displays the following output:
// Type1.cs(13,23): warning CS3001: Argument type 'uint' is not CLS-compliant
// Type1.cs(13,33): warning CS3001: Argument type 'uint?' is not CLS-compliant
// Type1.cs(19,26): warning CS3003: Type of 'InvoiceItem.Quantity' is not CLS-compliant
// Type1.cs(25,16): warning CS3003: Type of 'InvoiceItem.InvoiceId' is not CLS-compliant
<Assembly: CLSCompliant(True)>
Public Class InvoiceItem
Private invId As UInteger = 0
Private itemId As UInteger = 0
Private qty AS Nullable(Of UInteger)
Public Sub New(sku As UInteger, quantity As Nullable(Of UInteger))
itemId = sku
qty = quantity
End Sub
Public Property Quantity As Nullable(Of UInteger)
Get
Return qty
End Get
Set
qty = value
End Set
End Property
Public Property InvoiceId As UInteger
Get
Return invId
End Get
Set
invId = value
End Set
End Property
End Class
' The attempt to compile the example displays output similar to the following:
' Type1.vb(13) : warning BC40028: Type of parameter 'sku' is not CLS-compliant.
'
' Public Sub New(sku As UInteger, quantity As Nullable(Of UInteger))
' ~~~
' Type1.vb(13) : warning BC40041: Type 'UInteger' is not CLS-compliant.
'
' Public Sub New(sku As UInteger, quantity As Nullable(Of UInteger))
' ~~~~~~~~
' Type1.vb(18) : warning BC40041: Type 'UInteger' is not CLS-compliant.
'
' Public Property Quantity As Nullable(Of UInteger)
' ~~~~~~~~
' Type1.vb(27) : warning BC40027: Return type of function 'InvoiceId' is not CLS-compliant.
'
' Public Property InvoiceId As UInteger
' ~~~~~~~~~
A fordító figyelmeztetéseinek kiküszöböléséhez cserélje le a nem CLS-kompatibilis típusokat a nyilvános felületen megfelelő InvoiceItem
típusokra:
using System;
[assembly: CLSCompliant(true)]
public class InvoiceItem
{
private uint invId = 0;
private uint itemId = 0;
private Nullable<int> qty;
public InvoiceItem(int sku, Nullable<int> quantity)
{
if (sku <= 0)
throw new ArgumentOutOfRangeException("The item number is zero or negative.");
itemId = (uint) sku;
qty = quantity;
}
public Nullable<int> Quantity
{
get { return qty; }
set { qty = value; }
}
public int InvoiceId
{
get { return (int) invId; }
set {
if (value <= 0)
throw new ArgumentOutOfRangeException("The invoice number is zero or negative.");
invId = (uint) value; }
}
}
<Assembly: CLSCompliant(True)>
Public Class InvoiceItem
Private invId As UInteger = 0
Private itemId As UInteger = 0
Private qty AS Nullable(Of Integer)
Public Sub New(sku As Integer, quantity As Nullable(Of Integer))
If sku <= 0 Then
Throw New ArgumentOutOfRangeException("The item number is zero or negative.")
End If
itemId = CUInt(sku)
qty = quantity
End Sub
Public Property Quantity As Nullable(Of Integer)
Get
Return qty
End Get
Set
qty = value
End Set
End Property
Public Property InvoiceId As Integer
Get
Return CInt(invId)
End Get
Set
invId = CUInt(value)
End Set
End Property
End Class
A felsorolt típusokon kívül egyes típusok nem felelnek meg a CLS-nek. Ezek közé tartoznak a nem felügyelt mutatótípusok és a függvénymutató-típusok. Az alábbi példa egy fordítói figyelmeztetést generál, mert egy egész számra mutató mutatót használ egész számok tömbjének létrehozásához.
using System;
[assembly: CLSCompliant(true)]
public class ArrayHelper
{
unsafe public static Array CreateInstance(Type type, int* ptr, int items)
{
Array arr = Array.CreateInstance(type, items);
int* addr = ptr;
for (int ctr = 0; ctr < items; ctr++) {
int value = *addr;
arr.SetValue(value, ctr);
addr++;
}
return arr;
}
}
// The attempt to compile this example displays the following output:
// UnmanagedPtr1.cs(8,57): warning CS3001: Argument type 'int*' is not CLS-compliant
A CLS-kompatibilis absztrakt osztályok (azaz a C#-ban vagy a MustInherit
Visual Basicben megjelölt abstract
osztályok) esetében az osztály minden tagjának CLS-kompatibilisnek kell lennie.
Elnevezési konvenciók
Mivel egyes programozási nyelvek nem érzéketlenek a kis- és nagybetűkhez, az azonosítóknak (például a névterek, a típusok és a tagok neve) az esetnél nagyobb mértékben kell eltérniük. Két azonosító egyenértékűnek minősül, ha kisbetűs leképezéseik megegyeznek. Az alábbi C#-példa két nyilvános osztályt Person
person
és . Mivel csak esetükben különböznek egymástól, a C#-fordító nem CLS-kompatibilisként jelöli meg őket.
using System;
[assembly: CLSCompliant(true)]
public class Person : person
{
}
public class person
{
}
// Compilation produces a compiler warning like the following:
// Naming1.cs(11,14): warning CS3005: Identifier 'person' differing
// only in case is not CLS-compliant
// Naming1.cs(6,14): (Location of symbol related to previous warning)
A programozási nyelv azonosítóinak, például a névterek, a típusok és a tagok nevének meg kell felelniük a Unicode Szabványnak. Ez azt jelenti, hogy:
Az azonosító első karaktere lehet bármilyen Unicode-nagybetű, kisbetű, kisbetű, kisbetű, módosító betű, egyéb betű vagy betűszám. A Unicode-karakterkategóriákról további információt az enumerálásban System.Globalization.UnicodeCategory talál.
A következő karakterek bármelyik kategóriából származhatnak első karakterként, és tartalmazhatnak térköz nélküli jeleket, térköz-egyesítési jeleket, tizedes törteket, összekötő írásjeleket és formázási kódokat is.
Az azonosítók összehasonlítása előtt szűrje ki a formázási kódokat, és konvertálja az azonosítókat Unicode Normalization Form C formátumra, mivel egyetlen karaktert több UTF-16 kódolású kódegység képviselhet. Azok a karaktersorozatok, amelyek ugyanazt a kódegységet állítják elő a Unicode Normalization Form C-ben, nem CLS-kompatibilisek. Az alábbi példa egy elnevezett Å
tulajdonságot határoz meg, amely az ANGSTROM SIGN (U+212B) karakterből és egy második nevű Å
tulajdonságból áll, amely a LATIN NAGYBETŰS A KARAKTERBŐL ÁLL, A GYŰRŰVEL FENT (U+00C5). A C# és a Visual Basic fordítói nem CLS-kompatibilisként jelölik meg a forráskódot.
public class Size
{
private double a1;
private double a2;
public double Å
{
get { return a1; }
set { a1 = value; }
}
public double Å
{
get { return a2; }
set { a2 = value; }
}
}
// Compilation produces a compiler warning like the following:
// Naming2a.cs(16,18): warning CS3005: Identifier 'Size.Å' differing only in case is not
// CLS-compliant
// Naming2a.cs(10,18): (Location of symbol related to previous warning)
// Naming2a.cs(18,8): warning CS3005: Identifier 'Size.Å.get' differing only in case is not
// CLS-compliant
// Naming2a.cs(12,8): (Location of symbol related to previous warning)
// Naming2a.cs(19,8): warning CS3005: Identifier 'Size.Å.set' differing only in case is not
// CLS-compliant
// Naming2a.cs(13,8): (Location of symbol related to previous warning)
<Assembly: CLSCompliant(True)>
Public Class Size
Private a1 As Double
Private a2 As Double
Public Property Å As Double
Get
Return a1
End Get
Set
a1 = value
End Set
End Property
Public Property Å As Double
Get
Return a2
End Get
Set
a2 = value
End Set
End Property
End Class
' Compilation produces a compiler warning like the following:
' Naming1.vb(9) : error BC30269: 'Public Property Å As Double' has multiple definitions
' with identical signatures.
'
' Public Property Å As Double
' ~
Az adott hatókörön belüli tagneveknek (például a szerelvényen belüli névtereknek, a névtéren belüli típusoknak vagy a típuson belüli tagoknak) egyedinek kell lenniük, kivéve a túlterheléssel feloldott neveket. Ez a követelmény szigorúbb, mint a közös típusú rendszer, amely lehetővé teszi, hogy egy hatókörön belül több tag is azonos névvel rendelkezzen, feltéve, hogy különböző tagok (például az egyik metódus, a másik pedig mező). Különösen a típustagok esetében:
A mezőket és a beágyazott típusokat csak a név különbözteti meg.
Az azonos nevű metódusoknak, tulajdonságoknak és eseményeknek nem csupán a visszatérési típussal kell különbözniük.
Az alábbi példa azt a követelményt mutatja be, hogy a tagok nevének egyedinek kell lennie a hatókörükön belül. Egy olyan osztályt Converter
definiál, amely négy tagot tartalmaz.Conversion
A három metódus egy tulajdonság. A paramétert Int64 tartalmazó metódus egyedi névvel van elnevezve, de a paraméterrel rendelkező Int32 két metódus nem, mert a visszatérési érték nem tekinthető egy tag aláírásának. A Conversion
tulajdonság szintén sérti ezt a követelményt, mert a tulajdonságok neve nem lehet ugyanaz, mint a túlterhelt metódusok neve.
using System;
[assembly: CLSCompliant(true)]
public class Converter
{
public double Conversion(int number)
{
return (double) number;
}
public float Conversion(int number)
{
return (float) number;
}
public double Conversion(long number)
{
return (double) number;
}
public bool Conversion
{
get { return true; }
}
}
// Compilation produces a compiler error like the following:
// Naming3.cs(13,17): error CS0111: Type 'Converter' already defines a member called
// 'Conversion' with the same parameter types
// Naming3.cs(8,18): (Location of symbol related to previous error)
// Naming3.cs(23,16): error CS0102: The type 'Converter' already contains a definition for
// 'Conversion'
// Naming3.cs(8,18): (Location of symbol related to previous error)
<Assembly: CLSCompliant(True)>
Public Class Converter
Public Function Conversion(number As Integer) As Double
Return CDbl(number)
End Function
Public Function Conversion(number As Integer) As Single
Return CSng(number)
End Function
Public Function Conversion(number As Long) As Double
Return CDbl(number)
End Function
Public ReadOnly Property Conversion As Boolean
Get
Return True
End Get
End Property
End Class
' Compilation produces a compiler error like the following:
' Naming3.vb(8) : error BC30301: 'Public Function Conversion(number As Integer) As Double'
' and 'Public Function Conversion(number As Integer) As Single' cannot
' overload each other because they differ only by return types.
'
' Public Function Conversion(number As Integer) As Double
' ~~~~~~~~~~
' Naming3.vb(20) : error BC30260: 'Conversion' is already declared as 'Public Function
' Conversion(number As Integer) As Single' in this class.
'
' Public ReadOnly Property Conversion As Boolean
' ~~~~~~~~~~
Az egyes nyelvek egyedi kulcsszavakat tartalmaznak, így a közös nyelvi futtatókörnyezetet megcélzó nyelveknek bizonyos mechanizmusokat is biztosítaniuk kell a kulcsszavakkal egybeeső azonosítókra (például típusnevekre) való hivatkozáshoz. Például case
egy kulcsszó a C# és a Visual Basic nyelvben is. Az alábbi Visual Basic-példa azonban képes egyértelműsíteni a kulcsszóból case
elnevezett case
osztályt nyitó és záró zárójelek használatával. Ellenkező esetben a példa "A kulcsszó nem érvényes azonosítóként" hibaüzenet jelenik meg, és nem fordítódik le.
Public Class [case]
Private _id As Guid
Private name As String
Public Sub New(name As String)
_id = Guid.NewGuid()
Me.name = name
End Sub
Public ReadOnly Property ClientName As String
Get
Return name
End Get
End Property
End Class
Az alábbi C#-példa képes példányosítani az case
osztályt a @
szimbólum használatával, hogy egyértelműsítse az azonosítót a nyelvi kulcsszóból. Nélküle a C#-fordító két hibaüzenetet jelenít meg: "Típus várható" és "Érvénytelen kifejezés".
using System;
public class Example
{
public static void Main()
{
@case c = new @case("John");
Console.WriteLine(c.ClientName);
}
}
Típuskonverzió
A Common Language Specification két konverziós operátort határoz meg:
op_Implicit
, amelyet olyan átalakítások szélesítésére használnak, amelyek nem okoznak adatvesztést vagy pontosságot. A struktúra például tartalmaz egy túlterhelt operátortop_Implicit
, Decimal amely az integráltípusok és Char értékek értékeit értékekké Decimal alakítja.op_Explicit
, amelyet olyan konverziók szűkítésére használnak, amelyek nagyságvesztést eredményezhetnek (az érték kisebb tartományú értékké alakul át) vagy pontosságot. A struktúra például tartalmaz egy túlterhelt operátort, Decimal amely átalakítja Double az Single értékeket, és az értékeket integrál értékekké alakítja át, és Charaz értékeket Decimal pedig szerves értékekké alakítjaDecimal. DoubleSingleop_Explicit
Azonban nem minden nyelv támogatja az operátorok túlterhelését vagy az egyéni operátorok definícióját. Ha úgy dönt, hogy implementálja ezeket a konverziós operátorokat, alternatív módot is kell biztosítania a konvertálás végrehajtására. Javasoljuk, hogy xxx és To
xxx metódust adjon megFrom
.
Az alábbi példa a CLS-kompatibilis implicit és explicit konverziókat határozza meg. Létrehoz egy osztályt UDouble
, amely egy alá nem írt, dupla pontosságú lebegőpontos számot jelöl. Implicit konverziókat UDouble
Double biztosít az át- és a be- DoubleUDouble
és SingleUDouble
Single a UDouble
to . A metódust ToDouble
az implicit konverziós operátor és a ToSingle
, FromDouble
és FromSingle
metódusok alternatívaként definiálja az explicit konverziós operátorok alternatívaként.
using System;
public struct UDouble
{
private double number;
public UDouble(double value)
{
if (value < 0)
throw new InvalidCastException("A negative value cannot be converted to a UDouble.");
number = value;
}
public UDouble(float value)
{
if (value < 0)
throw new InvalidCastException("A negative value cannot be converted to a UDouble.");
number = value;
}
public static readonly UDouble MinValue = (UDouble) 0.0;
public static readonly UDouble MaxValue = (UDouble) Double.MaxValue;
public static explicit operator Double(UDouble value)
{
return value.number;
}
public static implicit operator Single(UDouble value)
{
if (value.number > (double) Single.MaxValue)
throw new InvalidCastException("A UDouble value is out of range of the Single type.");
return (float) value.number;
}
public static explicit operator UDouble(double value)
{
if (value < 0)
throw new InvalidCastException("A negative value cannot be converted to a UDouble.");
return new UDouble(value);
}
public static implicit operator UDouble(float value)
{
if (value < 0)
throw new InvalidCastException("A negative value cannot be converted to a UDouble.");
return new UDouble(value);
}
public static Double ToDouble(UDouble value)
{
return (Double) value;
}
public static float ToSingle(UDouble value)
{
return (float) value;
}
public static UDouble FromDouble(double value)
{
return new UDouble(value);
}
public static UDouble FromSingle(float value)
{
return new UDouble(value);
}
}
Public Structure UDouble
Private number As Double
Public Sub New(value As Double)
If value < 0 Then
Throw New InvalidCastException("A negative value cannot be converted to a UDouble.")
End If
number = value
End Sub
Public Sub New(value As Single)
If value < 0 Then
Throw New InvalidCastException("A negative value cannot be converted to a UDouble.")
End If
number = value
End Sub
Public Shared ReadOnly MinValue As UDouble = CType(0.0, UDouble)
Public Shared ReadOnly MaxValue As UDouble = Double.MaxValue
Public Shared Widening Operator CType(value As UDouble) As Double
Return value.number
End Operator
Public Shared Narrowing Operator CType(value As UDouble) As Single
If value.number > CDbl(Single.MaxValue) Then
Throw New InvalidCastException("A UDouble value is out of range of the Single type.")
End If
Return CSng(value.number)
End Operator
Public Shared Narrowing Operator CType(value As Double) As UDouble
If value < 0 Then
Throw New InvalidCastException("A negative value cannot be converted to a UDouble.")
End If
Return New UDouble(value)
End Operator
Public Shared Narrowing Operator CType(value As Single) As UDouble
If value < 0 Then
Throw New InvalidCastException("A negative value cannot be converted to a UDouble.")
End If
Return New UDouble(value)
End Operator
Public Shared Function ToDouble(value As UDouble) As Double
Return CType(value, Double)
End Function
Public Shared Function ToSingle(value As UDouble) As Single
Return CType(value, Single)
End Function
Public Shared Function FromDouble(value As Double) As UDouble
Return New UDouble(value)
End Function
Public Shared Function FromSingle(value As Single) As UDouble
Return New UDouble(value)
End Function
End Structure
Tömbök
A CLS-kompatibilis tömbök megfelelnek a következő szabályoknak:
A tömbök minden dimenziójának nulla alsó határával kell rendelkeznie. Az alábbi példa egy nem CLS-kompatibilis tömböt hoz létre, amelynek alsó határa egy. Az attribútum jelenléte CLSCompliantAttribute ellenére a fordító nem észleli, hogy a metódus által
Numbers.GetTenPrimes
visszaadott tömb nem CLS-kompatibilis.[assembly: CLSCompliant(true)] public class Numbers { public static Array GetTenPrimes() { Array arr = Array.CreateInstance(typeof(Int32), new int[] {10}, new int[] {1}); arr.SetValue(1, 1); arr.SetValue(2, 2); arr.SetValue(3, 3); arr.SetValue(5, 4); arr.SetValue(7, 5); arr.SetValue(11, 6); arr.SetValue(13, 7); arr.SetValue(17, 8); arr.SetValue(19, 9); arr.SetValue(23, 10); return arr; } }
<Assembly: CLSCompliant(True)> Public Class Numbers Public Shared Function GetTenPrimes() As Array Dim arr As Array = Array.CreateInstance(GetType(Int32), {10}, {1}) arr.SetValue(1, 1) arr.SetValue(2, 2) arr.SetValue(3, 3) arr.SetValue(5, 4) arr.SetValue(7, 5) arr.SetValue(11, 6) arr.SetValue(13, 7) arr.SetValue(17, 8) arr.SetValue(19, 9) arr.SetValue(23, 10) Return arr End Function End Class
Minden tömbelemnek CLS-kompatibilis típusokból kell állnia. Az alábbi példa két metódust határoz meg, amelyek nem CLS-kompatibilis tömböket adnak vissza. Az első értéktömböt UInt32 ad vissza. A második egy Object tömböt ad vissza, amely tartalmaz és UInt32 értékeket.Int32 Bár a fordító az első tömböt típusuk miatt nem megfelelőként azonosítja UInt32 , nem ismeri fel, hogy a második tömb nem CLS-kompatibilis elemeket tartalmaz.
using System; [assembly: CLSCompliant(true)] public class Numbers { public static UInt32[] GetTenPrimes() { uint[] arr = { 1u, 2u, 3u, 5u, 7u, 11u, 13u, 17u, 19u }; return arr; } public static Object[] GetFivePrimes() { Object[] arr = { 1, 2, 3, 5u, 7u }; return arr; } } // Compilation produces a compiler warning like the following: // Array2.cs(8,27): warning CS3002: Return type of 'Numbers.GetTenPrimes()' is not // CLS-compliant
<Assembly: CLSCompliant(True)> Public Class Numbers Public Shared Function GetTenPrimes() As UInt32() Return {1ui, 2ui, 3ui, 5ui, 7ui, 11ui, 13ui, 17ui, 19ui} End Function Public Shared Function GetFivePrimes() As Object() Dim arr() As Object = {1, 2, 3, 5ui, 7ui} Return arr End Function End Class ' Compilation produces a compiler warning like the following: ' warning BC40027: Return type of function 'GetTenPrimes' is not CLS-compliant. ' ' Public Shared Function GetTenPrimes() As UInt32() ' ~~~~~~~~~~~~
A tömbparaméterekkel rendelkező metódusok túlterhelésének feloldása a tömbök és az elemtípusuk alapján történik. Ezért a túlterhelt
GetSquares
metódusok következő definíciója a CLS-kompatibilis.using System; using System.Numerics; [assembly: CLSCompliant(true)] public class Numbers { public static byte[] GetSquares(byte[] numbers) { byte[] numbersOut = new byte[numbers.Length]; for (int ctr = 0; ctr < numbers.Length; ctr++) { int square = ((int) numbers[ctr]) * ((int) numbers[ctr]); if (square <= Byte.MaxValue) numbersOut[ctr] = (byte) square; // If there's an overflow, assign MaxValue to the corresponding // element. else numbersOut[ctr] = Byte.MaxValue; } return numbersOut; } public static BigInteger[] GetSquares(BigInteger[] numbers) { BigInteger[] numbersOut = new BigInteger[numbers.Length]; for (int ctr = 0; ctr < numbers.Length; ctr++) numbersOut[ctr] = numbers[ctr] * numbers[ctr]; return numbersOut; } }
Imports System.Numerics <Assembly: CLSCompliant(True)> Public Module Numbers Public Function GetSquares(numbers As Byte()) As Byte() Dim numbersOut(numbers.Length - 1) As Byte For ctr As Integer = 0 To numbers.Length - 1 Dim square As Integer = (CInt(numbers(ctr)) * CInt(numbers(ctr))) If square <= Byte.MaxValue Then numbersOut(ctr) = CByte(square) ' If there's an overflow, assign MaxValue to the corresponding ' element. Else numbersOut(ctr) = Byte.MaxValue End If Next Return numbersOut End Function Public Function GetSquares(numbers As BigInteger()) As BigInteger() Dim numbersOut(numbers.Length - 1) As BigInteger For ctr As Integer = 0 To numbers.Length - 1 numbersOut(ctr) = numbers(ctr) * numbers(ctr) Next Return numbersOut End Function End Module
Interfészek
A CLS-kompatibilis felületek tulajdonságokat, eseményeket és virtuális metódusokat definiálhatnak (implementálás nélküli metódusokat). A CLS-kompatibilis felület nem rendelkezhet a következők egyikével sem:
Statikus metódusok vagy statikus mezők. A C# és a Visual Basic fordítói is fordítóhibákat okoznak, ha statikus tagot határoz meg egy felületen.
Mezők. A C# és a Visual Basic fordítói is fordítóhibákat okoznak, ha egy mezőt definiál egy felületen.
Nem CLS-kompatibilis metódusok. A következő felületdefiníció például tartalmaz egy metódust,
INumber.GetUnsigned
amely nem CLS-kompatibilisként van megjelölve. Ez a példa egy fordító figyelmeztetést hoz létre.using System; [assembly:CLSCompliant(true)] public interface INumber { int Length(); [CLSCompliant(false)] ulong GetUnsigned(); } // Attempting to compile the example displays output like the following: // Interface2.cs(8,32): warning CS3010: 'INumber.GetUnsigned()': CLS-compliant interfaces // must have only CLS-compliant members
<Assembly: CLSCompliant(True)> Public Interface INumber Function Length As Integer <CLSCompliant(False)> Function GetUnsigned As ULong End Interface ' Attempting to compile the example displays output like the following: ' Interface2.vb(9) : warning BC40033: Non CLS-compliant 'function' is not allowed in a ' CLS-compliant interface. ' ' <CLSCompliant(False)> Function GetUnsigned As ULong ' ~~~~~~~~~~~
A szabály miatt a CLS-kompatibilis típusok nem szükségesek a nem CLS-kompatibilis tagok implementálásához. Ha egy CLS-kompatibilis keretrendszer olyan osztályt tesz elérhetővé, amely nem CLS-kompatibilis felületet implementál, akkor konkrét implementációkat is biztosítania kell az összes nem CLS-kompatibilis tag számára.
A CLS-kompatibilis nyelvfordítóknak lehetővé kell tenniük, hogy az osztály külön implementációkat biztosítson azoknak a tagoknak, akiknek ugyanaz a neve és aláírása több felületen. A C# és a Visual Basic egyaránt támogatja az explicit felületi implementációkat az azonos nevű metódusok különböző implementációinak biztosításához. A Visual Basic támogatja a Implements
kulcsszót is, amely lehetővé teszi, hogy explicit módon jelölje ki, hogy egy adott tag melyik felületet és tagot implementálja. Az alábbi példa ezt a forgatókönyvet egy olyan osztály definiálásával Temperature
szemlélteti, amely explicit felületi implementációként implementálja az és IFahrenheit
az ICelsius
interfészeket.
using System;
[assembly: CLSCompliant(true)]
public interface IFahrenheit
{
decimal GetTemperature();
}
public interface ICelsius
{
decimal GetTemperature();
}
public class Temperature : ICelsius, IFahrenheit
{
private decimal _value;
public Temperature(decimal value)
{
// We assume that this is the Celsius value.
_value = value;
}
decimal IFahrenheit.GetTemperature()
{
return _value * 9 / 5 + 32;
}
decimal ICelsius.GetTemperature()
{
return _value;
}
}
public class Example
{
public static void Main()
{
Temperature temp = new Temperature(100.0m);
ICelsius cTemp = temp;
IFahrenheit fTemp = temp;
Console.WriteLine("Temperature in Celsius: {0} degrees",
cTemp.GetTemperature());
Console.WriteLine("Temperature in Fahrenheit: {0} degrees",
fTemp.GetTemperature());
}
}
// The example displays the following output:
// Temperature in Celsius: 100.0 degrees
// Temperature in Fahrenheit: 212.0 degrees
<Assembly: CLSCompliant(True)>
Public Interface IFahrenheit
Function GetTemperature() As Decimal
End Interface
Public Interface ICelsius
Function GetTemperature() As Decimal
End Interface
Public Class Temperature : Implements ICelsius, IFahrenheit
Private _value As Decimal
Public Sub New(value As Decimal)
' We assume that this is the Celsius value.
_value = value
End Sub
Public Function GetFahrenheit() As Decimal _
Implements IFahrenheit.GetTemperature
Return _value * 9 / 5 + 32
End Function
Public Function GetCelsius() As Decimal _
Implements ICelsius.GetTemperature
Return _value
End Function
End Class
Module Example
Public Sub Main()
Dim temp As New Temperature(100.0d)
Console.WriteLine("Temperature in Celsius: {0} degrees",
temp.GetCelsius())
Console.WriteLine("Temperature in Fahrenheit: {0} degrees",
temp.GetFahrenheit())
End Sub
End Module
' The example displays the following output:
' Temperature in Celsius: 100.0 degrees
' Temperature in Fahrenheit: 212.0 degrees
Enumerálások
A CLS-kompatibilis enumerálásoknak az alábbi szabályokat kell követniük:
Az enumerálás alapjául szolgáló típusnak belső CLS-kompatibilis egész számnak (Byte, Int16, , Int32vagy Int64) kell lennie. Az alábbi kód például egy olyan enumerálást próbál definiálni, amelynek a mögöttes típusa egy UInt32 fordítói figyelmeztetés.
using System; [assembly: CLSCompliant(true)] public enum Size : uint { Unspecified = 0, XSmall = 1, Small = 2, Medium = 3, Large = 4, XLarge = 5 }; public class Clothing { public string Name; public string Type; public string Size; } // The attempt to compile the example displays a compiler warning like the following: // Enum3.cs(6,13): warning CS3009: 'Size': base type 'uint' is not CLS-compliant
<Assembly: CLSCompliant(True)> Public Enum Size As UInt32 Unspecified = 0 XSmall = 1 Small = 2 Medium = 3 Large = 4 XLarge = 5 End Enum Public Class Clothing Public Name As String Public Type As String Public Size As Size End Class ' The attempt to compile the example displays a compiler warning like the following: ' Enum3.vb(6) : warning BC40032: Underlying type 'UInt32' of Enum is not CLS-compliant. ' ' Public Enum Size As UInt32 ' ~~~~
Az enumerálási típusnak egyetlen példánymezővel
Value__
kell rendelkeznie, amely az FieldAttributes.RTSpecialName attribútummal van megjelölve. Így implicit módon hivatkozhat a mezőértékre.Az enumerálás olyan konstans statikus mezőket tartalmaz, amelyek típusai megegyeznek az enumerálás típusával. Ha például egy számbavételt
State
határoz meg az ésState.Off
az , értékekkelState.On
,State.On
ésState.Off
mindkettő olyan konstans statikus mező, amelynek típusa .State
Kétféle enumerálás létezik:
Egy egymást kizáró, elnevezett egész számértékeket tartalmazó enumerálás. Ezt az enumerálási típust az egyéni attribútum hiánya System.FlagsAttribute jelzi.
Egy olyan számbavétel, amely olyan bitjelölőket jelöl, amelyek összevonhatók egy névtelen érték létrehozásához. Ezt az enumerálási típust az egyéni attribútum jelenléte System.FlagsAttribute jelzi.
További információkért tekintse meg a szerkezet dokumentációját Enum .
Az enumerálás értéke nem korlátozódik a megadott értékek tartományára. Más szóval az enumerálásban az értékek tartománya a mögöttes érték tartománya. A metódussal Enum.IsDefined meghatározhatja, hogy egy megadott érték tagja-e az enumerálásnak.
Általában írja be a tagokat
A Common Language Specification megköveteli, hogy az összes mező és metódus egy adott osztály tagjaként legyen elérhető. Ezért a globális statikus mezők és metódusok (azaz a típuson kívül definiált statikus mezők vagy metódusok) nem clS-kompatibilisek. Ha egy globális mezőt vagy metódust próbál belefoglalni a forráskódba, a C# és a Visual Basic fordítói is fordítóhibát okoznak.
A Common Language Specification csak a szabványos felügyelt hívási konvenciót támogatja. Nem támogatja a nem felügyelt hívási konvenciók és metódusok használatát a kulcsszóval megjelölt változó argumentumlistákkal varargs
. A standard felügyelt hívási konvencióval kompatibilis változó argumentumlistákhoz használja az ParamArrayAttribute attribútumot vagy az egyes nyelv implementációját, például a params
C# kulcsszót és a Visual Basicben használt kulcsszót ParamArray
.
A tagok akadálymentessége
Az örökölt tag felülírása nem módosíthatja az adott tag akadálymentességét. Egy alaposztály nyilvános metódusát például nem lehet felülírni egy származtatott osztály privát metódusával. Egyetlen kivétel van: egy protected internal
(C#-ban) vagy Protected Friend
egy (Visual Basic-ben) tag egy olyan szerelvényben, amelyet egy másik szerelvény típusának felül kell bírálnia. Ebben az esetben a felülbírálás akadálymentessége a következő Protected
: .
Az alábbi példa azt a hibát szemlélteti, amely akkor jön létre, amikor a CLSCompliantAttribute attribútum true
értéke , és Human
– amely egy származtatott Animal
osztály – megpróbálja módosítani a Species
tulajdonság akadálymentességét nyilvánosról privátra. A példa sikeresen lefordítható, ha az akadálymentessége nyilvánosra módosul.
using System;
[assembly: CLSCompliant(true)]
public class Animal
{
private string _species;
public Animal(string species)
{
_species = species;
}
public virtual string Species
{
get { return _species; }
}
public override string ToString()
{
return _species;
}
}
public class Human : Animal
{
private string _name;
public Human(string name) : base("Homo Sapiens")
{
_name = name;
}
public string Name
{
get { return _name; }
}
private override string Species
{
get { return base.Species; }
}
public override string ToString()
{
return _name;
}
}
public class Example
{
public static void Main()
{
Human p = new Human("John");
Console.WriteLine(p.Species);
Console.WriteLine(p.ToString());
}
}
// The example displays the following output:
// error CS0621: 'Human.Species': virtual or abstract members cannot be private
<Assembly: CLSCompliant(True)>
Public Class Animal
Private _species As String
Public Sub New(species As String)
_species = species
End Sub
Public Overridable ReadOnly Property Species As String
Get
Return _species
End Get
End Property
Public Overrides Function ToString() As String
Return _species
End Function
End Class
Public Class Human : Inherits Animal
Private _name As String
Public Sub New(name As String)
MyBase.New("Homo Sapiens")
_name = name
End Sub
Public ReadOnly Property Name As String
Get
Return _name
End Get
End Property
Private Overrides ReadOnly Property Species As String
Get
Return MyBase.Species
End Get
End Property
Public Overrides Function ToString() As String
Return _name
End Function
End Class
Public Module Example
Public Sub Main()
Dim p As New Human("John")
Console.WriteLine(p.Species)
Console.WriteLine(p.ToString())
End Sub
End Module
' The example displays the following output:
' 'Private Overrides ReadOnly Property Species As String' cannot override
' 'Public Overridable ReadOnly Property Species As String' because
' they have different access levels.
'
' Private Overrides ReadOnly Property Species As String
A tag aláírásában szereplő típusoknak akadálymentesnek kell lenniük, amikor az adott tag elérhető. Ez például azt jelenti, hogy a nyilvános tagok nem tartalmazhatnak olyan paramétert, amelynek típusa privát, védett vagy belső. Az alábbi példa azt a fordítóhibát szemlélteti, amely akkor következik be, ha egy StringWrapper
osztálykonstruktor egy belső StringOperationType
számbavételi értéket tesz elérhetővé, amely meghatározza a sztringértékek burkolásának módját.
using System;
using System.Text;
public class StringWrapper
{
string internalString;
StringBuilder internalSB = null;
bool useSB = false;
public StringWrapper(StringOperationType type)
{
if (type == StringOperationType.Normal) {
useSB = false;
}
else {
useSB = true;
internalSB = new StringBuilder();
}
}
// The remaining source code...
}
internal enum StringOperationType { Normal, Dynamic }
// The attempt to compile the example displays the following output:
// error CS0051: Inconsistent accessibility: parameter type
// 'StringOperationType' is less accessible than method
// 'StringWrapper.StringWrapper(StringOperationType)'
Imports System.Text
<Assembly: CLSCompliant(True)>
Public Class StringWrapper
Dim internalString As String
Dim internalSB As StringBuilder = Nothing
Dim useSB As Boolean = False
Public Sub New(type As StringOperationType)
If type = StringOperationType.Normal Then
useSB = False
Else
internalSB = New StringBuilder()
useSB = True
End If
End Sub
' The remaining source code...
End Class
Friend Enum StringOperationType As Integer
Normal = 0
Dynamic = 1
End Enum
' The attempt to compile the example displays the following output:
' error BC30909: 'type' cannot expose type 'StringOperationType'
' outside the project through class 'StringWrapper'.
'
' Public Sub New(type As StringOperationType)
' ~~~~~~~~~~~~~~~~~~~
Általános típusok és tagok
A beágyazott típusok mindig legalább annyi általános paramétert rendelkeznek, mint a beágyazási típusuk. Ezek pozíció szerint felelnek meg a beágyazási típus általános paramétereinek. Az általános típus új általános paramétereket is tartalmazhat.
Egy adott típus általános típusparaméterei és beágyazott típusai közötti kapcsolatot az egyes nyelvek szintaxisa rejtheti el. Az alábbi példában egy általános típus Outer<T>
két beágyazott osztályt Inner1A
és Inner1B<U>
. A metódus hívásai ToString
, amelyektől Object.ToString()az egyes osztályok öröklődnek, azt mutatják, hogy minden beágyazott osztály tartalmazza a benne található osztály típusparamétereit.
using System;
[assembly:CLSCompliant(true)]
public class Outer<T>
{
T value;
public Outer(T value)
{
this.value = value;
}
public class Inner1A : Outer<T>
{
public Inner1A(T value) : base(value)
{ }
}
public class Inner1B<U> : Outer<T>
{
U value2;
public Inner1B(T value1, U value2) : base(value1)
{
this.value2 = value2;
}
}
}
public class Example
{
public static void Main()
{
var inst1 = new Outer<String>("This");
Console.WriteLine(inst1);
var inst2 = new Outer<String>.Inner1A("Another");
Console.WriteLine(inst2);
var inst3 = new Outer<String>.Inner1B<int>("That", 2);
Console.WriteLine(inst3);
}
}
// The example displays the following output:
// Outer`1[System.String]
// Outer`1+Inner1A[System.String]
// Outer`1+Inner1B`1[System.String,System.Int32]
<Assembly: CLSCompliant(True)>
Public Class Outer(Of T)
Dim value As T
Public Sub New(value As T)
Me.value = value
End Sub
Public Class Inner1A : Inherits Outer(Of T)
Public Sub New(value As T)
MyBase.New(value)
End Sub
End Class
Public Class Inner1B(Of U) : Inherits Outer(Of T)
Dim value2 As U
Public Sub New(value1 As T, value2 As U)
MyBase.New(value1)
Me.value2 = value2
End Sub
End Class
End Class
Public Module Example
Public Sub Main()
Dim inst1 As New Outer(Of String)("This")
Console.WriteLine(inst1)
Dim inst2 As New Outer(Of String).Inner1A("Another")
Console.WriteLine(inst2)
Dim inst3 As New Outer(Of String).Inner1B(Of Integer)("That", 2)
Console.WriteLine(inst3)
End Sub
End Module
' The example displays the following output:
' Outer`1[System.String]
' Outer`1+Inner1A[System.String]
' Outer`1+Inner1B`1[System.String,System.Int32]
Az általános típusnevek az "n" űrlapnévben vannak kódolva, ahol a név a típusnév, a " egy karakterkonstans, n pedig a típuson deklarált paraméterek száma, beágyazott általános típusok esetében pedig az újonnan bevezetett típusparaméterek száma. Az általános típusnevek kódolása elsősorban azoknak a fejlesztőknek érdekes, akik a clS-panasz generikus típusainak elérésére használják a tükrözést egy kódtárban.
Ha általános típusra alkalmaz kényszereket, a kényszerként használt típusoknak IS CLS-kompatibilisnek kell lenniük. Az alábbi példa egy olyan osztályt BaseClass
határoz meg, amely nem CLS-kompatibilis, és egy általános osztályt, BaseCollection
amelynek típusparaméteréből BaseClass
származnia kell. BaseClass
Mivel azonban nem CLS-kompatibilis, a fordító figyelmeztetést ad ki.
using System;
[assembly:CLSCompliant(true)]
[CLSCompliant(false)] public class BaseClass
{}
public class BaseCollection<T> where T : BaseClass
{}
// Attempting to compile the example displays the following output:
// warning CS3024: Constraint type 'BaseClass' is not CLS-compliant
<Assembly: CLSCompliant(True)>
<CLSCompliant(False)> Public Class BaseClass
End Class
Public Class BaseCollection(Of T As BaseClass)
End Class
' Attempting to compile the example displays the following output:
' warning BC40040: Generic parameter constraint type 'BaseClass' is not
' CLS-compliant.
'
' Public Class BaseCollection(Of T As BaseClass)
' ~~~~~~~~~
Ha egy általános típus egy általános alaptípusból származik, újra kell definiálnia minden korlátozást, hogy az garantálhassa, hogy az alaptípusra vonatkozó korlátozások is teljesülnek. Az alábbi példa olyan típust Number<T>
határoz meg, amely bármilyen numerikus típust képviselhet. Egy lebegőpontos értéket képviselő osztályt is definiál FloatingPoint<T>
. A forráskód fordítása azonban nem sikerült, mert nem alkalmazza a korlátozást Number<T>
(a T értéktípusnak kell lennie) a következőre FloatingPoint<T>
: .
using System;
[assembly:CLSCompliant(true)]
public class Number<T> where T : struct
{
// use Double as the underlying type, since its range is a superset of
// the ranges of all numeric types except BigInteger.
protected double number;
public Number(T value)
{
try {
this.number = Convert.ToDouble(value);
}
catch (OverflowException e) {
throw new ArgumentException("value is too large.", e);
}
catch (InvalidCastException e) {
throw new ArgumentException("The value parameter is not numeric.", e);
}
}
public T Add(T value)
{
return (T) Convert.ChangeType(number + Convert.ToDouble(value), typeof(T));
}
public T Subtract(T value)
{
return (T) Convert.ChangeType(number - Convert.ToDouble(value), typeof(T));
}
}
public class FloatingPoint<T> : Number<T>
{
public FloatingPoint(T number) : base(number)
{
if (typeof(float) == number.GetType() ||
typeof(double) == number.GetType() ||
typeof(decimal) == number.GetType())
this.number = Convert.ToDouble(number);
else
throw new ArgumentException("The number parameter is not a floating-point number.");
}
}
// The attempt to compile the example displays the following output:
// error CS0453: The type 'T' must be a non-nullable value type in
// order to use it as parameter 'T' in the generic type or method 'Number<T>'
<Assembly: CLSCompliant(True)>
Public Class Number(Of T As Structure)
' Use Double as the underlying type, since its range is a superset of
' the ranges of all numeric types except BigInteger.
Protected number As Double
Public Sub New(value As T)
Try
Me.number = Convert.ToDouble(value)
Catch e As OverflowException
Throw New ArgumentException("value is too large.", e)
Catch e As InvalidCastException
Throw New ArgumentException("The value parameter is not numeric.", e)
End Try
End Sub
Public Function Add(value As T) As T
Return CType(Convert.ChangeType(number + Convert.ToDouble(value), GetType(T)), T)
End Function
Public Function Subtract(value As T) As T
Return CType(Convert.ChangeType(number - Convert.ToDouble(value), GetType(T)), T)
End Function
End Class
Public Class FloatingPoint(Of T) : Inherits Number(Of T)
Public Sub New(number As T)
MyBase.New(number)
If TypeOf number Is Single Or
TypeOf number Is Double Or
TypeOf number Is Decimal Then
Me.number = Convert.ToDouble(number)
Else
throw new ArgumentException("The number parameter is not a floating-point number.")
End If
End Sub
End Class
' The attempt to compile the example displays the following output:
' error BC32105: Type argument 'T' does not satisfy the 'Structure'
' constraint for type parameter 'T'.
'
' Public Class FloatingPoint(Of T) : Inherits Number(Of T)
' ~
A példa sikeresen lefordítja, ha a korlátozás hozzá van adva az FloatingPoint<T>
osztályhoz.
using System;
[assembly:CLSCompliant(true)]
public class Number<T> where T : struct
{
// use Double as the underlying type, since its range is a superset of
// the ranges of all numeric types except BigInteger.
protected double number;
public Number(T value)
{
try {
this.number = Convert.ToDouble(value);
}
catch (OverflowException e) {
throw new ArgumentException("value is too large.", e);
}
catch (InvalidCastException e) {
throw new ArgumentException("The value parameter is not numeric.", e);
}
}
public T Add(T value)
{
return (T) Convert.ChangeType(number + Convert.ToDouble(value), typeof(T));
}
public T Subtract(T value)
{
return (T) Convert.ChangeType(number - Convert.ToDouble(value), typeof(T));
}
}
public class FloatingPoint<T> : Number<T> where T : struct
{
public FloatingPoint(T number) : base(number)
{
if (typeof(float) == number.GetType() ||
typeof(double) == number.GetType() ||
typeof(decimal) == number.GetType())
this.number = Convert.ToDouble(number);
else
throw new ArgumentException("The number parameter is not a floating-point number.");
}
}
<Assembly: CLSCompliant(True)>
Public Class Number(Of T As Structure)
' Use Double as the underlying type, since its range is a superset of
' the ranges of all numeric types except BigInteger.
Protected number As Double
Public Sub New(value As T)
Try
Me.number = Convert.ToDouble(value)
Catch e As OverflowException
Throw New ArgumentException("value is too large.", e)
Catch e As InvalidCastException
Throw New ArgumentException("The value parameter is not numeric.", e)
End Try
End Sub
Public Function Add(value As T) As T
Return CType(Convert.ChangeType(number + Convert.ToDouble(value), GetType(T)), T)
End Function
Public Function Subtract(value As T) As T
Return CType(Convert.ChangeType(number - Convert.ToDouble(value), GetType(T)), T)
End Function
End Class
Public Class FloatingPoint(Of T As Structure) : Inherits Number(Of T)
Public Sub New(number As T)
MyBase.New(number)
If TypeOf number Is Single Or
TypeOf number Is Double Or
TypeOf number Is Decimal Then
Me.number = Convert.ToDouble(number)
Else
throw new ArgumentException("The number parameter is not a floating-point number.")
End If
End Sub
End Class
A Common Language Specification egy konzervatív példányonkénti modellt ír elő a beágyazott típusok és a védett tagok számára. A nyitott általános típusok nem tehetnek közzé olyan mezőket vagy tagokat aláírásokkal, amelyek egy beágyazott, védett általános típus meghatározott példányát tartalmazzák. Az általános alaposztály vagy felület adott példányosítását kiterjesztő nem általános típusok nem tehetnek közzé olyan mezőket vagy tagokat aláírásokkal, amelyek egy beágyazott, védett általános típus eltérő példányát tartalmazzák.
Az alábbi példa egy általános típust C1<T>
(vagy C1(Of T)
a Visual Basicben) és egy védett osztályt C1<T>.N
határoz meg (vagy C1(Of T).N
a Visual Basicben). C1<T>
két metódusa van, M1
és M2
. Azonban nem felel meg a CLS-nek, M1
mert egy (vagy C1(Of Integer).N
) objektumot próbál visszaadni C1<int>.N
a C1<T-ből> (vagy C1(Of T)
). A második osztály a C2
(vagyC1(Of Long)
) osztályból C1<long>
származik. Két módszere van, M3
és M4
. M3
nem FELEL meg a CLS-nek, mert egy (vagy ) objektumot próbál visszaadni C1<int>.N
a (vagy C1(Of Integer).N
) alosztályból.C1<long>
A nyelvi fordítók még korlátozóbbak lehetnek. Ebben a példában a Visual Basic hibát jelenít meg a fordítási M4
kísérlet során.
using System;
[assembly:CLSCompliant(true)]
public class C1<T>
{
protected class N { }
protected void M1(C1<int>.N n) { } // Not CLS-compliant - C1<int>.N not
// accessible from within C1<T> in all
// languages
protected void M2(C1<T>.N n) { } // CLS-compliant – C1<T>.N accessible
// inside C1<T>
}
public class C2 : C1<long>
{
protected void M3(C1<int>.N n) { } // Not CLS-compliant – C1<int>.N is not
// accessible in C2 (extends C1<long>)
protected void M4(C1<long>.N n) { } // CLS-compliant, C1<long>.N is
// accessible in C2 (extends C1<long>)
}
// Attempting to compile the example displays output like the following:
// Generics4.cs(9,22): warning CS3001: Argument type 'C1<int>.N' is not CLS-compliant
// Generics4.cs(18,22): warning CS3001: Argument type 'C1<int>.N' is not CLS-compliant
<Assembly: CLSCompliant(True)>
Public Class C1(Of T)
Protected Class N
End Class
Protected Sub M1(n As C1(Of Integer).N) ' Not CLS-compliant - C1<int>.N not
' accessible from within C1(Of T) in all
End Sub ' languages
Protected Sub M2(n As C1(Of T).N) ' CLS-compliant – C1(Of T).N accessible
End Sub ' inside C1(Of T)
End Class
Public Class C2 : Inherits C1(Of Long)
Protected Sub M3(n As C1(Of Integer).N) ' Not CLS-compliant – C1(Of Integer).N is not
End Sub ' accessible in C2 (extends C1(Of Long))
Protected Sub M4(n As C1(Of Long).N)
End Sub
End Class
' Attempting to compile the example displays output like the following:
' error BC30508: 'n' cannot expose type 'C1(Of Integer).N' in namespace
' '<Default>' through class 'C1'.
'
' Protected Sub M1(n As C1(Of Integer).N) ' Not CLS-compliant - C1<int>.N not
' ~~~~~~~~~~~~~~~~
' error BC30389: 'C1(Of T).N' is not accessible in this context because
' it is 'Protected'.
'
' Protected Sub M3(n As C1(Of Integer).N) ' Not CLS-compliant - C1(Of Integer).N is not
'
' ~~~~~~~~~~~~~~~~
'
' error BC30389: 'C1(Of T).N' is not accessible in this context because it is 'Protected'.
'
' Protected Sub M4(n As C1(Of Long).N)
' ~~~~~~~~~~~~~
Konstruktorok
A CLS-kompatibilis osztályokban és struktúrákban lévő konstruktoroknak az alábbi szabályokat kell követniük:
A származtatott osztály konstruktorának meg kell hívnia az alaposztály példánykonstruktorát, mielőtt hozzáfér az örökölt példányadatokhoz. Ennek a követelménynek az az oka, hogy az alaposztály konstruktorait nem öröklik a származtatott osztályaik. Ez a szabály nem vonatkozik olyan struktúrákra, amelyek nem támogatják a közvetlen öröklést.
A fordítók általában a CLS-megfelelőségtől függetlenül kényszerítik ezt a szabályt, ahogy az az alábbi példában is látható. Létrehoz egy
Doctor
osztályból származtatott osztálytPerson
, de azDoctor
osztály nem hívja meg az osztálykonstruktort azPerson
örökölt példánymezők inicializálásához.using System; [assembly: CLSCompliant(true)] public class Person { private string fName, lName, _id; public Person(string firstName, string lastName, string id) { if (String.IsNullOrEmpty(firstName + lastName)) throw new ArgumentNullException("Either a first name or a last name must be provided."); fName = firstName; lName = lastName; _id = id; } public string FirstName { get { return fName; } } public string LastName { get { return lName; } } public string Id { get { return _id; } } public override string ToString() { return String.Format("{0}{1}{2}", fName, String.IsNullOrEmpty(fName) ? "" : " ", lName); } } public class Doctor : Person { public Doctor(string firstName, string lastName, string id) { } public override string ToString() { return "Dr. " + base.ToString(); } } // Attempting to compile the example displays output like the following: // ctor1.cs(45,11): error CS1729: 'Person' does not contain a constructor that takes 0 // arguments // ctor1.cs(10,11): (Location of symbol related to previous error)
<Assembly: CLSCompliant(True)> Public Class Person Private fName, lName, _id As String Public Sub New(firstName As String, lastName As String, id As String) If String.IsNullOrEmpty(firstName + lastName) Then Throw New ArgumentNullException("Either a first name or a last name must be provided.") End If fName = firstName lName = lastName _id = id End Sub Public ReadOnly Property FirstName As String Get Return fName End Get End Property Public ReadOnly Property LastName As String Get Return lName End Get End Property Public ReadOnly Property Id As String Get Return _id End Get End Property Public Overrides Function ToString() As String Return String.Format("{0}{1}{2}", fName, If(String.IsNullOrEmpty(fName), "", " "), lName) End Function End Class Public Class Doctor : Inherits Person Public Sub New(firstName As String, lastName As String, id As String) End Sub Public Overrides Function ToString() As String Return "Dr. " + MyBase.ToString() End Function End Class ' Attempting to compile the example displays output like the following: ' Ctor1.vb(46) : error BC30148: First statement of this 'Sub New' must be a call ' to 'MyBase.New' or 'MyClass.New' because base class 'Person' of 'Doctor' does ' not have an accessible 'Sub New' that can be called with no arguments. ' ' Public Sub New() ' ~~~
Objektumkonstruktor csak objektum létrehozása esetén hívható meg. Ezenkívül egy objektum nem inicializálható kétszer. Ez például azt jelenti, hogy Object.MemberwiseClone a deszerializálási módszereknek nem szabad konstruktorokat hívniuk.
Tulajdonságok
A CLS-kompatibilis típusok tulajdonságainak az alábbi szabályokat kell követniük:
A tulajdonságnak rendelkeznie kell egy beállítóval, egy getterrel vagy mindkettővel. A szerelvényben ezek speciális metódusokként vannak implementálva, ami azt jelenti, hogy külön metódusként jelennek meg (a getter neve
get_
tulajdonságnév, a setter pedigset_
tulajdonságnév) a szerelvény metaadatai között.SpecialName
A C# és a Visual Basic fordítói automatikusan kényszerítik ezt a szabályt az CLSCompliantAttribute attribútum alkalmazása nélkül.A tulajdonság típusa a tulajdonság getter visszatérési típusa és a beállító utolsó argumentuma. Ezeknek a típusoknak CLS-kompatibilisnek kell lenniük, és az argumentumok nem rendelhetők hozzá a tulajdonsághoz hivatkozással (vagyis nem kezelhetők mutatókkal).
Ha egy tulajdonság rendelkezik getterrel és setterrel is, akkor mindkettőnek virtuálisnak, statikusnak vagy mindkét példánynak kell lennie. A C# és a Visual Basic fordítói automatikusan érvényesítik ezt a szabályt a tulajdonságdefiníció szintaxisán keresztül.
esemény
Az eseményt a neve és típusa határozza meg. Az esemény típusa egy delegált, amely az esemény jelzésére szolgál. Például az AppDomain.AssemblyResolve esemény típusa ResolveEventHandler. Az esemény mellett három, az eseménynéven alapuló névvel rendelkező metódus biztosítja az esemény implementációját, és a szerelvény metaadataiban szereplőként van megjelölve SpecialName
:
Egy EventName nevű
add_
eseménykezelő hozzáadásának metódusa. Az esemény esemény-előfizetési metódusa például a AppDomain.AssemblyResolve neveadd_AssemblyResolve
.Egy EventName nevű
remove_
eseménykezelő eltávolításának módszere. Az esemény eltávolítási módszere például a AppDomain.AssemblyResolve neveremove_AssemblyResolve
.Az esemény bekövetkezésének jelzésére szolgáló metódus, neve
raise_
EventName.
Feljegyzés
A Common Language Specification eseményekkel kapcsolatos szabályainak többségét nyelvi fordítók implementálják, és transzparensek az összetevők fejlesztői számára.
Az esemény hozzáadásának, eltávolításának és növelésének módszereinek azonos akadálymentességgel kell rendelkezniük. Mindnek statikusnak, példánynak vagy virtuálisnak kell lennie. Az esemény hozzáadásának és eltávolításának módszerei egy olyan paramétert használnak, amelynek típusa az eseménymeghatalmazási típus. A hozzáadási és eltávolítási módszereknek jelen kell lenniük, vagy mindkettőnek hiányzik.
Az alábbi példa egy CLS-kompatibilis osztályt határoz meg, Temperature
amely eseményt TemperatureChanged
hoz létre, ha a hőmérséklet változása két érték között egyenlő vagy meghaladja a küszöbértéket. Az Temperature
osztály explicit módon definiál egy metódust raise_TemperatureChanged
, hogy szelektíven végrehajthassa az eseménykezelőket.
using System;
using System.Collections;
using System.Collections.Generic;
[assembly: CLSCompliant(true)]
public class TemperatureChangedEventArgs : EventArgs
{
private Decimal originalTemp;
private Decimal newTemp;
private DateTimeOffset when;
public TemperatureChangedEventArgs(Decimal original, Decimal @new, DateTimeOffset time)
{
originalTemp = original;
newTemp = @new;
when = time;
}
public Decimal OldTemperature
{
get { return originalTemp; }
}
public Decimal CurrentTemperature
{
get { return newTemp; }
}
public DateTimeOffset Time
{
get { return when; }
}
}
public delegate void TemperatureChanged(Object sender, TemperatureChangedEventArgs e);
public class Temperature
{
private struct TemperatureInfo
{
public Decimal Temperature;
public DateTimeOffset Recorded;
}
public event TemperatureChanged TemperatureChanged;
private Decimal previous;
private Decimal current;
private Decimal tolerance;
private List<TemperatureInfo> tis = new List<TemperatureInfo>();
public Temperature(Decimal temperature, Decimal tolerance)
{
current = temperature;
TemperatureInfo ti = new TemperatureInfo();
ti.Temperature = temperature;
tis.Add(ti);
ti.Recorded = DateTimeOffset.UtcNow;
this.tolerance = tolerance;
}
public Decimal CurrentTemperature
{
get { return current; }
set {
TemperatureInfo ti = new TemperatureInfo();
ti.Temperature = value;
ti.Recorded = DateTimeOffset.UtcNow;
previous = current;
current = value;
if (Math.Abs(current - previous) >= tolerance)
raise_TemperatureChanged(new TemperatureChangedEventArgs(previous, current, ti.Recorded));
}
}
public void raise_TemperatureChanged(TemperatureChangedEventArgs eventArgs)
{
if (TemperatureChanged == null)
return;
foreach (TemperatureChanged d in TemperatureChanged.GetInvocationList()) {
if (d.Method.Name.Contains("Duplicate"))
Console.WriteLine("Duplicate event handler; event handler not executed.");
else
d.Invoke(this, eventArgs);
}
}
}
public class Example
{
public Temperature temp;
public static void Main()
{
Example ex = new Example();
}
public Example()
{
temp = new Temperature(65, 3);
temp.TemperatureChanged += this.TemperatureNotification;
RecordTemperatures();
Example ex = new Example(temp);
ex.RecordTemperatures();
}
public Example(Temperature t)
{
temp = t;
RecordTemperatures();
}
public void RecordTemperatures()
{
temp.TemperatureChanged += this.DuplicateTemperatureNotification;
temp.CurrentTemperature = 66;
temp.CurrentTemperature = 63;
}
internal void TemperatureNotification(Object sender, TemperatureChangedEventArgs e)
{
Console.WriteLine("Notification 1: The temperature changed from {0} to {1}", e.OldTemperature, e.CurrentTemperature);
}
public void DuplicateTemperatureNotification(Object sender, TemperatureChangedEventArgs e)
{
Console.WriteLine("Notification 2: The temperature changed from {0} to {1}", e.OldTemperature, e.CurrentTemperature);
}
}
Imports System.Collections
Imports System.Collections.Generic
<Assembly: CLSCompliant(True)>
Public Class TemperatureChangedEventArgs : Inherits EventArgs
Private originalTemp As Decimal
Private newTemp As Decimal
Private [when] As DateTimeOffset
Public Sub New(original As Decimal, [new] As Decimal, [time] As DateTimeOffset)
originalTemp = original
newTemp = [new]
[when] = [time]
End Sub
Public ReadOnly Property OldTemperature As Decimal
Get
Return originalTemp
End Get
End Property
Public ReadOnly Property CurrentTemperature As Decimal
Get
Return newTemp
End Get
End Property
Public ReadOnly Property [Time] As DateTimeOffset
Get
Return [when]
End Get
End Property
End Class
Public Delegate Sub TemperatureChanged(sender As Object, e As TemperatureChangedEventArgs)
Public Class Temperature
Private Structure TemperatureInfo
Dim Temperature As Decimal
Dim Recorded As DateTimeOffset
End Structure
Public Event TemperatureChanged As TemperatureChanged
Private previous As Decimal
Private current As Decimal
Private tolerance As Decimal
Private tis As New List(Of TemperatureInfo)
Public Sub New(temperature As Decimal, tolerance As Decimal)
current = temperature
Dim ti As New TemperatureInfo()
ti.Temperature = temperature
ti.Recorded = DateTimeOffset.UtcNow
tis.Add(ti)
Me.tolerance = tolerance
End Sub
Public Property CurrentTemperature As Decimal
Get
Return current
End Get
Set
Dim ti As New TemperatureInfo
ti.Temperature = value
ti.Recorded = DateTimeOffset.UtcNow
previous = current
current = value
If Math.Abs(current - previous) >= tolerance Then
raise_TemperatureChanged(New TemperatureChangedEventArgs(previous, current, ti.Recorded))
End If
End Set
End Property
Public Sub raise_TemperatureChanged(eventArgs As TemperatureChangedEventArgs)
If TemperatureChangedEvent Is Nothing Then Exit Sub
Dim ListenerList() As System.Delegate = TemperatureChangedEvent.GetInvocationList()
For Each d As TemperatureChanged In TemperatureChangedEvent.GetInvocationList()
If d.Method.Name.Contains("Duplicate") Then
Console.WriteLine("Duplicate event handler; event handler not executed.")
Else
d.Invoke(Me, eventArgs)
End If
Next
End Sub
End Class
Public Class Example
Public WithEvents temp As Temperature
Public Shared Sub Main()
Dim ex As New Example()
End Sub
Public Sub New()
temp = New Temperature(65, 3)
RecordTemperatures()
Dim ex As New Example(temp)
ex.RecordTemperatures()
End Sub
Public Sub New(t As Temperature)
temp = t
RecordTemperatures()
End Sub
Public Sub RecordTemperatures()
temp.CurrentTemperature = 66
temp.CurrentTemperature = 63
End Sub
Friend Shared Sub TemperatureNotification(sender As Object, e As TemperatureChangedEventArgs) _
Handles temp.TemperatureChanged
Console.WriteLine("Notification 1: The temperature changed from {0} to {1}", e.OldTemperature, e.CurrentTemperature)
End Sub
Friend Shared Sub DuplicateTemperatureNotification(sender As Object, e As TemperatureChangedEventArgs) _
Handles temp.TemperatureChanged
Console.WriteLine("Notification 2: The temperature changed from {0} to {1}", e.OldTemperature, e.CurrentTemperature)
End Sub
End Class
Túlterhelések
A Common Language Specification a következő követelményeket támasztja a túlterhelt tagokra vonatkozóan:
A tagok túlterhelhetők a paraméterek száma és a paraméterek típusa alapján. A metódusra vagy paraméterre alkalmazott meghívási konvenciók, visszatérési típus, egyéni módosítók, és hogy a paramétereket érték vagy hivatkozás alapján adja-e át a rendszer, a túlterhelések közötti különbséget nem veszi figyelembe. Példaként tekintse meg annak a követelménynek a kódját, amely szerint a neveknek egyedinek kell lenniük az Elnevezési konvenciók szakaszban található hatókörön belül.
Csak tulajdonságok és metódusok terhelhetők túl. A mezők és események nem terhelhetők túl.
Az általános metódusok túlterhelhetők az általános paraméterek száma alapján.
Feljegyzés
Az op_Explicit
operátorok op_Implicit
kivételt képeznek azon szabály alól, amely a visszaadott értéket nem tekinti a túlterhelés feloldására szolgáló metódus-aláírásnak. Ez a két operátor a paraméterek és a visszatérési érték alapján túlterhelhető.
Kivételek
A kivételobjektumoknak származnia kell egy System.Exception másik típusból, amelyből System.Exceptionszármazik. Az alábbi példa azt a fordítóhibát szemlélteti, amely akkor következik be, ha egy névvel ellátott ErrorClass
egyéni osztályt használnak a kivételkezeléshez.
using System;
[assembly: CLSCompliant(true)]
public class ErrorClass
{
string msg;
public ErrorClass(string errorMessage)
{
msg = errorMessage;
}
public string Message
{
get { return msg; }
}
}
public static class StringUtilities
{
public static string[] SplitString(this string value, int index)
{
if (index < 0 | index > value.Length) {
ErrorClass badIndex = new ErrorClass("The index is not within the string.");
throw badIndex;
}
string[] retVal = { value.Substring(0, index - 1),
value.Substring(index) };
return retVal;
}
}
// Compilation produces a compiler error like the following:
// Exceptions1.cs(26,16): error CS0155: The type caught or thrown must be derived from
// System.Exception
Imports System.Runtime.CompilerServices
<Assembly: CLSCompliant(True)>
Public Class ErrorClass
Dim msg As String
Public Sub New(errorMessage As String)
msg = errorMessage
End Sub
Public ReadOnly Property Message As String
Get
Return msg
End Get
End Property
End Class
Public Module StringUtilities
<Extension()> Public Function SplitString(value As String, index As Integer) As String()
If index < 0 Or index > value.Length Then
Dim BadIndex As New ErrorClass("The index is not within the string.")
Throw BadIndex
End If
Dim retVal() As String = {value.Substring(0, index - 1),
value.Substring(index)}
Return retVal
End Function
End Module
' Compilation produces a compiler error like the following:
' Exceptions1.vb(27) : error BC30665: 'Throw' operand must derive from 'System.Exception'.
'
' Throw BadIndex
' ~~~~~~~~~~~~~~
A hiba kijavításához az osztálynak a ErrorClass
következőtől System.Exceptionkell örökölnie: Emellett felül kell bírálni a Message
tulajdonságot. Az alábbi példa ezeket a hibákat egy CLS-kompatibilis osztály definiálásához ErrorClass
javítja ki.
using System;
[assembly: CLSCompliant(true)]
public class ErrorClass : Exception
{
string msg;
public ErrorClass(string errorMessage)
{
msg = errorMessage;
}
public override string Message
{
get { return msg; }
}
}
public static class StringUtilities
{
public static string[] SplitString(this string value, int index)
{
if (index < 0 | index > value.Length) {
ErrorClass badIndex = new ErrorClass("The index is not within the string.");
throw badIndex;
}
string[] retVal = { value.Substring(0, index - 1),
value.Substring(index) };
return retVal;
}
}
Imports System.Runtime.CompilerServices
<Assembly: CLSCompliant(True)>
Public Class ErrorClass : Inherits Exception
Dim msg As String
Public Sub New(errorMessage As String)
msg = errorMessage
End Sub
Public Overrides ReadOnly Property Message As String
Get
Return msg
End Get
End Property
End Class
Public Module StringUtilities
<Extension()> Public Function SplitString(value As String, index As Integer) As String()
If index < 0 Or index > value.Length Then
Dim BadIndex As New ErrorClass("The index is not within the string.")
Throw BadIndex
End If
Dim retVal() As String = {value.Substring(0, index - 1),
value.Substring(index)}
Return retVal
End Function
End Module
Attribútumok
A .NET-szerelvényekben az egyéni attribútumok bővíthető mechanizmust biztosítanak az egyéni attribútumok tárolására és a programozási objektumok metaadatainak lekérésére, például szerelvényekre, típusokra, tagokra és metódusparaméterekre. Az egyéni attribútumoknak a System.Attribútumból vagy a rendszerből származtatott típusból System.Attribute
kell származnia.
Az alábbi példa megsérti ezt a szabályt. Olyan osztályt NumericAttribute
határoz meg, amely nem származik belőle System.Attribute. A fordítóhiba csak a nem CLS-kompatibilis attribútum alkalmazásakor jelentkezik, az osztály definiálásakor nem.
using System;
[assembly: CLSCompliant(true)]
[AttributeUsageAttribute(AttributeTargets.Class | AttributeTargets.Struct)]
public class NumericAttribute
{
private bool _isNumeric;
public NumericAttribute(bool isNumeric)
{
_isNumeric = isNumeric;
}
public bool IsNumeric
{
get { return _isNumeric; }
}
}
[Numeric(true)] public struct UDouble
{
double Value;
}
// Compilation produces a compiler error like the following:
// Attribute1.cs(22,2): error CS0616: 'NumericAttribute' is not an attribute class
// Attribute1.cs(7,14): (Location of symbol related to previous error)
<Assembly: CLSCompliant(True)>
<AttributeUsageAttribute(AttributeTargets.Class Or AttributeTargets.Struct)> _
Public Class NumericAttribute
Private _isNumeric As Boolean
Public Sub New(isNumeric As Boolean)
_isNumeric = isNumeric
End Sub
Public ReadOnly Property IsNumeric As Boolean
Get
Return _isNumeric
End Get
End Property
End Class
<Numeric(True)> Public Structure UDouble
Dim Value As Double
End Structure
' Compilation produces a compiler error like the following:
' error BC31504: 'NumericAttribute' cannot be used as an attribute because it
' does not inherit from 'System.Attribute'.
'
' <Numeric(True)> Public Structure UDouble
' ~~~~~~~~~~~~~
A CLS-kompatibilis attribútum konstruktora vagy tulajdonságai csak a következő típusokat tehetik elérhetővé:
Az alábbi példa egy attribútumból származó osztályt DescriptionAttribute
határoz meg. Az osztálykonstruktor típusparaméterrel Descriptor
rendelkezik, így az osztály nem CLS-kompatibilis. A C#-fordító figyelmeztetést ad ki, de sikeresen lefordítja, míg a Visual Basic fordító nem bocsát ki figyelmeztetést vagy hibát.
using System;
[assembly:CLSCompliantAttribute(true)]
public enum DescriptorType { type, member };
public class Descriptor
{
public DescriptorType Type;
public String Description;
}
[AttributeUsage(AttributeTargets.All)]
public class DescriptionAttribute : Attribute
{
private Descriptor desc;
public DescriptionAttribute(Descriptor d)
{
desc = d;
}
public Descriptor Descriptor
{ get { return desc; } }
}
// Attempting to compile the example displays output like the following:
// warning CS3015: 'DescriptionAttribute' has no accessible
// constructors which use only CLS-compliant types
<Assembly: CLSCompliantAttribute(True)>
Public Enum DescriptorType As Integer
Type = 0
Member = 1
End Enum
Public Class Descriptor
Public Type As DescriptorType
Public Description As String
End Class
<AttributeUsage(AttributeTargets.All)> _
Public Class DescriptionAttribute : Inherits Attribute
Private desc As Descriptor
Public Sub New(d As Descriptor)
desc = d
End Sub
Public ReadOnly Property Descriptor As Descriptor
Get
Return desc
End Get
End Property
End Class
A CLSCompliantAttribute attribútum
A CLSCompliantAttribute attribútum azt jelzi, hogy egy programelem megfelel-e a Common Language Specification szabványnak. A CLSCompliantAttribute(Boolean) konstruktor egyetlen kötelező paramétert ( isCompliant) tartalmaz, amely azt jelzi, hogy a programelem CLS-kompatibilis-e.
Fordításkor a fordító észleli a CLS-kompatibilisnek vélt nem megfelelő elemeket, és figyelmeztetést ad ki. A fordító nem ad ki figyelmeztetést azokra a típusokra vagy tagokra, amelyek kifejezetten nem megfelelőnek vannak nyilvánítva.
Az összetevő-fejlesztők kétféleképpen használhatják az CLSCompliantAttribute
attribútumot:
A nyilvános felület CLS-kompatibilis összetevő által közzétett részeinek és a NEM CLS-kompatibilis részeknek a meghatározása. Ha az attribútumot adott programelemek CLS-kompatibilisként való megjelölésére használják, annak használata garantálja, hogy ezek az elemek a .NET-et megcélozó összes nyelvről és eszközről elérhetők legyenek.
Annak biztosítása érdekében, hogy az összetevőtár nyilvános felülete csak a CLS-kompatibilis programelemeket tegye elérhetővé. Ha az elemek nem CLS-kompatibilisek, a fordítók általában figyelmeztetést adnak ki.
Figyelmeztetés
Bizonyos esetekben a nyelvfordítók a CLS-kompatibilis szabályokat kényszerítik, függetlenül attól, hogy az CLSCompliantAttribute
attribútumot használják-e. Ha például egy statikus tagot egy felületen definiál, azzal megsérti a CLS-szabályt. Ebben a tekintetben, ha ( static
C#-ban) vagy Shared
(Visual Basic)-tagot definiál egy felületen, akkor a C# és a Visual Basic fordítói is hibaüzenetet jelenítenek meg, és nem fordítják le az alkalmazást.
Az CLSCompliantAttribute attribútum egy AttributeUsageAttribute olyan attribútummal van megjelölve, amelynek értéke AttributeTargets.All. Ez az érték lehetővé teszi, hogy az attribútumot bármely programelemre alkalmazza, beleértve a CLSCompliantAttribute szerelvényeket, modulokat, típusokat (osztályok, struktúrák, enumerálások, interfészek és meghatalmazottak), típustagokat (konstruktorokat, metódusokat, tulajdonságokat, mezőket és eseményeket), paramétereket, általános paramétereket és visszatérési értékeket. A gyakorlatban azonban csak szerelvényekre, típusokra és típustagokra kell alkalmaznia az attribútumot. Ellenkező esetben a fordítók figyelmen kívül hagyják az attribútumot, és továbbra is generálnak fordítói figyelmeztetéseket, amikor nem megfelelő paraméterrel, általános paraméterrel vagy visszatérési értékkel találkoznak a tár nyilvános felületén.
Az attribútum értékét a CLSCompliantAttribute program tartalmazott elemei öröklik. Ha például egy szerelvény CLS-kompatibilisként van megjelölve, annak típusai szintén CLS-kompatibilisek. Ha egy típus CLS-kompatibilisként van megjelölve, a beágyazott típusok és a tagok szintén CLS-kompatibilisek.
Az örökölt megfelelőséget explicit módon felülbírálhatja úgy, hogy az CLSCompliantAttribute attribútumot egy tartalmazott programelemre alkalmazza. Használhatja például az CLSCompliantAttribute attribútumot egy isCompliant
olyan értékkel false
, amely egy nem megfelelő típust határoz meg egy megfelelő szerelvényben, és az attribútum értéke isCompliant
true
alapján megadhatja a megfelelő típust egy nem megfelelő szerelvényben. A nem megfelelő tagokat megfelelő típusban is definiálhatja. A nem megfelelő típusoknak azonban nem lehetnek megfelelő tagjai, ezért nem használhatja az attribútumot isCompliant
olyan értékkel, amely felülbírálja a nem megfelelő típus öröklését true
.
Összetevők fejlesztésekor mindig az attribútumot kell használnia annak jelzésére, hogy a CLSCompliantAttribute szerelvény, annak típusai és tagjai CLS-kompatibilisek-e.
CLS-kompatibilis összetevők létrehozása:
Használja a CLSCompliantAttribute szerelvényt CLS-kompatibilisként való megjelöléséhez.
Jelölje meg a nem CLS-kompatibilis szerelvény nyilvánosan közzétett típusait nem megfelelőként.
A CLS-kompatibilis típusok nyilvánosan közzétett tagjainak megjelölése nem megfelelőként.
Adjon meg egy CLS-kompatibilis alternatívát a nem CLS-kompatibilis tagok számára.
Ha sikeresen megjelölte az összes nem megfelelő típust és tagot, a fordító nem bocsáthat ki megfelelőségi figyelmeztetéseket. Meg kell azonban jelölnie, hogy mely tagok nem CLS-kompatibilisek, és sorolja fel a CLS-kompatibilis alternatíváikat a termékdokumentációban.
Az alábbi példa az CLSCompliantAttribute attribútumot használja egy CLS-kompatibilis szerelvény és egy típus meghatározására, CharacterUtilities
amely két nem CLS-kompatibilis taggal rendelkezik. Mivel mindkét tag címkézve van az CLSCompliant(false)
attribútummal, a fordító nem hoz létre figyelmeztetéseket. Az osztály emellett CLS-kompatibilis alternatívát is kínál mindkét módszerhez. Általában csak két túlterhelést adnánk hozzá a ToUTF16
módszerhez, hogy CLS-kompatibilis alternatívákat biztosítsunk. Mivel azonban a metódusok nem terhelhetők túl a visszatérési érték alapján, a CLS-kompatibilis metódusok neve eltér a nem megfelelő metódusok nevétől.
using System;
using System.Text;
[assembly:CLSCompliant(true)]
public class CharacterUtilities
{
[CLSCompliant(false)] public static ushort ToUTF16(String s)
{
s = s.Normalize(NormalizationForm.FormC);
return Convert.ToUInt16(s[0]);
}
[CLSCompliant(false)] public static ushort ToUTF16(Char ch)
{
return Convert.ToUInt16(ch);
}
// CLS-compliant alternative for ToUTF16(String).
public static int ToUTF16CodeUnit(String s)
{
s = s.Normalize(NormalizationForm.FormC);
return (int) Convert.ToUInt16(s[0]);
}
// CLS-compliant alternative for ToUTF16(Char).
public static int ToUTF16CodeUnit(Char ch)
{
return Convert.ToInt32(ch);
}
public bool HasMultipleRepresentations(String s)
{
String s1 = s.Normalize(NormalizationForm.FormC);
return s.Equals(s1);
}
public int GetUnicodeCodePoint(Char ch)
{
if (Char.IsSurrogate(ch))
throw new ArgumentException("ch cannot be a high or low surrogate.");
return Char.ConvertToUtf32(ch.ToString(), 0);
}
public int GetUnicodeCodePoint(Char[] chars)
{
if (chars.Length > 2)
throw new ArgumentException("The array has too many characters.");
if (chars.Length == 2) {
if (! Char.IsSurrogatePair(chars[0], chars[1]))
throw new ArgumentException("The array must contain a low and a high surrogate.");
else
return Char.ConvertToUtf32(chars[0], chars[1]);
}
else {
return Char.ConvertToUtf32(chars.ToString(), 0);
}
}
}
Imports System.Text
<Assembly: CLSCompliant(True)>
Public Class CharacterUtilities
<CLSCompliant(False)> Public Shared Function ToUTF16(s As String) As UShort
s = s.Normalize(NormalizationForm.FormC)
Return Convert.ToUInt16(s(0))
End Function
<CLSCompliant(False)> Public Shared Function ToUTF16(ch As Char) As UShort
Return Convert.ToUInt16(ch)
End Function
' CLS-compliant alternative for ToUTF16(String).
Public Shared Function ToUTF16CodeUnit(s As String) As Integer
s = s.Normalize(NormalizationForm.FormC)
Return CInt(Convert.ToInt16(s(0)))
End Function
' CLS-compliant alternative for ToUTF16(Char).
Public Shared Function ToUTF16CodeUnit(ch As Char) As Integer
Return Convert.ToInt32(ch)
End Function
Public Function HasMultipleRepresentations(s As String) As Boolean
Dim s1 As String = s.Normalize(NormalizationForm.FormC)
Return s.Equals(s1)
End Function
Public Function GetUnicodeCodePoint(ch As Char) As Integer
If Char.IsSurrogate(ch) Then
Throw New ArgumentException("ch cannot be a high or low surrogate.")
End If
Return Char.ConvertToUtf32(ch.ToString(), 0)
End Function
Public Function GetUnicodeCodePoint(chars() As Char) As Integer
If chars.Length > 2 Then
Throw New ArgumentException("The array has too many characters.")
End If
If chars.Length = 2 Then
If Not Char.IsSurrogatePair(chars(0), chars(1)) Then
Throw New ArgumentException("The array must contain a low and a high surrogate.")
Else
Return Char.ConvertToUtf32(chars(0), chars(1))
End If
Else
Return Char.ConvertToUtf32(chars.ToString(), 0)
End If
End Function
End Class
Ha nem tárat, hanem alkalmazást fejleszt (vagyis nem olyan típusokat vagy tagokat tesz ki, amelyeket más alkalmazásfejlesztők használhatnak), az alkalmazás által használt programelemek CLS-megfelelősége csak akkor érdekes, ha a nyelv nem támogatja őket. Ebben az esetben a nyelvfordító hibát fog generálni, amikor nem CLS-kompatibilis elemet próbál használni.
Nyelvek közötti együttműködés
A nyelvi függetlenségnek van néhány lehetséges jelentése. Az egyik jelentés magában foglalja az egyik nyelven írt típusok zökkenőmentes használatát egy másik nyelven írt alkalmazásból. A második jelentés, amely a cikk középpontjában áll, magában foglalja a több nyelven írt kód egyetlen .NET-szerelvénybe való kombinálását.
Az alábbi példa a nyelvek közötti együttműködést szemlélteti egy Utilities.dll nevű osztálytár létrehozásával, NumericLib
amely két osztályt és StringLib
egy osztályt tartalmaz. Az NumericLib
osztály C#-ban van megírva, az StringLib
osztály pedig Visual Basicben. Az alábbiakban a forráskódot StringUtil.vb
vizsgáljuk meg, amely egyetlen tagot ToTitleCase
tartalmaz az osztályban StringLib
.
Imports System.Collections.Generic
Imports System.Runtime.CompilerServices
Public Module StringLib
Private exclusions As List(Of String)
Sub New()
Dim words() As String = {"a", "an", "and", "of", "the"}
exclusions = New List(Of String)
exclusions.AddRange(words)
End Sub
<Extension()> _
Public Function ToTitleCase(title As String) As String
Dim words() As String = title.Split()
Dim result As String = String.Empty
For ctr As Integer = 0 To words.Length - 1
Dim word As String = words(ctr)
If ctr = 0 OrElse Not exclusions.Contains(word.ToLower()) Then
result += word.Substring(0, 1).ToUpper() + _
word.Substring(1).ToLower()
Else
result += word.ToLower()
End If
If ctr <= words.Length - 1 Then
result += " "
End If
Next
Return result
End Function
End Module
Itt található a NumberUtil.cs forráskódja, amely egy olyan osztályt NumericLib
határoz meg, amelynek két tagja van, IsEven
és NearZero
.
using System;
public static class NumericLib
{
public static bool IsEven(this IConvertible number)
{
if (number is Byte ||
number is SByte ||
number is Int16 ||
number is UInt16 ||
number is Int32 ||
number is UInt32 ||
number is Int64)
return Convert.ToInt64(number) % 2 == 0;
else if (number is UInt64)
return ((ulong) number) % 2 == 0;
else
throw new NotSupportedException("IsEven called for a non-integer value.");
}
public static bool NearZero(double number)
{
return Math.Abs(number) < .00001;
}
}
Ha a két osztályt egyetlen szerelvénybe szeretné csomagolni, modulba kell őket fordítania. A Visual Basic forráskódfájl modulba fordításához használja a következő parancsot:
vbc /t:module StringUtil.vb
A Visual Basic fordító parancssori szintaxisával kapcsolatos további információkért lásd : Build from the Parancssor.
A C# forráskódfájl modulba fordításához használja a következő parancsot:
csc /t:module NumberUtil.cs
Ezután a Linker beállításaival lefordíthatja a két modult egy szerelvénybe:
link numberutil.netmodule stringutil.netmodule /out:UtilityLib.dll /dll
Az alábbi példa ezután meghívja a metódusokat és StringLib.ToTitleCase
a NumericLib.NearZero
metódusokat. A Visual Basic-kód és a C#-kód egyaránt hozzáfér mindkét osztály metódusaihoz.
using System;
public class Example
{
public static void Main()
{
Double dbl = 0.0 - Double.Epsilon;
Console.WriteLine(NumericLib.NearZero(dbl));
string s = "war and peace";
Console.WriteLine(s.ToTitleCase());
}
}
// The example displays the following output:
// True
// War and Peace
Module Example
Public Sub Main()
Dim dbl As Double = 0.0 - Double.Epsilon
Console.WriteLine(NumericLib.NearZero(dbl))
Dim s As String = "war and peace"
Console.WriteLine(s.ToTitleCase())
End Sub
End Module
' The example displays the following output:
' True
' War and Peace
A Visual Basic-kód fordításához használja a következő parancsot:
vbc example.vb /r:UtilityLib.dll
A C# használatával történő fordításhoz módosítsa a fordító vbc
csc
nevét a következőre, és módosítsa a fájlkiterjesztést .vb-ről.cs:
csc example.cs /r:UtilityLib.dll