Sprachenunabhängigkeit und sprachunabhängige KomponentenLanguage Independence and Language-Independent Components

Das .NET Framework ist sprachneutral.The .NET Framework is language independent. Das bedeutet, dass ein Entwickler in einer der zahlreichen Sprachen entwickeln kann, die auf .NET Framework ausgerichtet sind, z. B. C#, C++/CLI, Eiffel, F#, IronPython, IronRuby, PowerBuilder, Visual Basic, Visual COBOL und Windows PowerShell.This means that, as a developer, you can develop in one of the many languages that target the .NET Framework, such as C#, C++/CLI, Eiffel, F#, IronPython, IronRuby, PowerBuilder, Visual Basic, Visual COBOL, and Windows PowerShell. Sie können auf die Typen und Member von Klassenbibliotheken, die für .NET Framework entwickelt wurden, zugreifen, ohne die Sprache, in der sie ursprünglich geschrieben wurden, kennen zu müssen und ohne den Konventionen der Originalsprache folgen zu müssen.You can access the types and members of class libraries developed for the .NET Framework without having to know the language in which they were originally written and without having to follow any of the original language's conventions. Wenn Sie ein Komponentenentwickler sind, kann von allen .NET Framework-Apps sprachenunabhängig auf die Komponente zugegriffen werden.If you are a component developer, your component can be accessed by any .NET Framework app regardless of its language.

Hinweis

In diesem Artikel wird das Erstellen sprachunabhängiger Komponenten erläutert. Diese Komponenten können von Apps verwendet werden, die in einer beliebigen Sprache geschrieben wurden.This first part of this article discusses creating language-independent components—that is, components that can be consumed by apps that are written in any language. Sie können auch eine einzelne Komponente oder App aus Quellcode erstellen, der in mehreren Sprachen geschrieben wurde. Weitere Informationen finden Sie im zweiten Teil dieses Artikels unter Sprachübergreifende Interoperabilität.You can also create a single component or app from source code written in multiple languages; see Cross-Language Interoperability in the second part of this article.

Um vollständig mit anderen Objekten zu interagieren, die in irgendeiner Programmiersprache geschrieben wurden, müssen die Objekte den Aufrufern nur die Funktionen verfügbar machen, die allen Sprachen gemeinsam sind.To fully interact with other objects written in any language, objects must expose to callers only those features that are common to all languages. Dieser gemeinsame Satz von Funktionen wird von der CLS (Common Language Specification) definiert. Das ist ein Satz von Regeln, die für generierte Assemblys gelten.This common set of features is defined by the Common Language Specification (CLS), which is a set of rules that apply to generated assemblies. Die Common Language Specification wird in der Partition I, in den Klauseln 7 bis 11 im ECMA 335-Standard: Common Language Infrastructure definiert.The Common Language Specification is defined in Partition I, Clauses 7 through 11 of the ECMA-335 Standard: Common Language Infrastructure.

Wenn die Komponente der Common Language Specification entspricht, ist sichergestellt, dass sie CLS-kompatibel ist, und dass vom Code in Assemblys, die in irgendeiner CLS unterstützenden Programmiersprache geschrieben wurden, aus auf sie zugegriffen werden kann.If your component conforms to the Common Language Specification, it is guaranteed to be CLS-compliant and can be accessed from code in assemblies written in any programming language that supports the CLS. Sie können bestimmen, ob die Komponente zur Kompilierzeit der Common Language Specification entspricht, indem Sie das CLSCompliantAttribute-Attribut auf den Quellcode anwenden.You can determine whether your component conforms to the Common Language Specification at compile time by applying the CLSCompliantAttribute attribute to your source code. Weitere Informationen finden Sie im Abschnitt zum CLSCompliantAttribute-Attribut.For more information, see The CLSCompliantAttribute attribute.

In diesem Artikel:In this article:

CLS-KompatibilitätsregelnCLS compliance rules

In diesem Abschnitt werden die Regeln zum Erstellen einer CLS-kompatiblen Komponente beschrieben.This section discusses the rules for creating a CLS-compliant component. Eine vollständige Liste der Regeln finden Sie unter Partition I, Klausel 11 im ECMA 335-Standard: Common Language Infrastructure.For a complete list of rules, see Partition I, Clause 11 of the ECMA-335 Standard: Common Language Infrastructure.

Hinweis

In der Common Language Specification wird für jede Regel der CLS-Kompatibilität erläutert, wie sie auf Consumer (Entwickler, die programmgesteuert auf eine CLS-kompatible Komponente zugreifen), Frameworks (Entwickler, die einen Sprachcompiler zum Erstellen von CLS-kompatiblen Bibliotheken verwenden) und Extender (Entwickler, die zum Erstellen CLS-kompatibler Komponenten ein Tool, wie einen Sprachcompiler oder einen Codeparser, erstellen) anzuwenden ist.The Common Language Specification discusses each rule for CLS compliance as it applies to consumers (developers who are programmatically accessing a component that is CLS-compliant), frameworks (developers who are using a language compiler to create CLS-compliant libraries), and extenders (developers who are creating a tool such as a language compiler or a code parser that creates CLS-compliant components). In diesem Artikel wird auf die Anwendbarkeit der Regeln für Frameworks eingegangen.This article focuses on the rules as they apply to frameworks. Beachten Sie allerdings, dass möglicherweise einige der Regeln für Extender auch auf Assemblys anwendbar sind, die mithilfe von "Reflection.Emit" erstellt werden.Note, though, that some of the rules that apply to extenders may also apply to assemblies that are created using Reflection.Emit.

Um eine sprachenneutrale Komponente zu entwerfen, müssen Sie nur die CLS-Kompatibilitätregeln auf die öffentliche Schnittstelle der Komponente anwenden.To design a component that is language independent, you only need to apply the rules for CLS compliance to your component's public interface. Die private Implementierung muss nicht mit der Spezifikation konform sein.Your private implementation does not have to conform to the specification.

Wichtig

Die Regeln für CLS-Kompatibilität gelten nur für die öffentlichen Schnittstelle einer Komponente, nicht für die private Implementierung.The rules for CLS compliance apply only to a component's public interface, not to its private implementation.

Zum Beispiel sind ganze Zahlen ohne Vorzeichen, außer Byte, nicht CLS-kompatibel.For example, unsigned integers other than Byte are not CLS-compliant. Da die Person-Klasse im folgenden Beispiel eine Age-Eigenschaft des Typs UInt16 verfügbar macht, zeigt der folgende Code eine Compilerwarnung an.Because the Person class in the following example exposes an Age property of type UInt16, the following code displays a compiler warning.

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
'                                ~~~

Sie können CLS-Kompatibilität für die Person-Klasse erreichen, indem Sie den Typ der Age-Eigenschaft von UInt16 auf Int16 ändern. Das ist eine CLS-kompatible ganze Zahl mit Vorzeichen und einer Länge von 16 Bit.You can make the Person class CLS-compliant by changing the type of Age property from UInt16 to Int16, which is a CLS-compliant, 16-bit signed integer. Sie müssen den Typ des privaten personAge-Felds nicht ändern.You do not have to change the type of the private personAge field.

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

Die öffentliche Schnittstelle einer Bibliothek besteht aus folgenden Elementen:A library's public interface consists of the following:

  • Definitionen öffentlicher KlassenDefinitions of public classes.

  • Definitionen öffentlicher Member von öffentlichen Klassen sowie in Definitionen von Membern, auf die abgeleitete Klassen zugreifen können (d. h. geschützte Member).Definitions of the public members of public classes, and definitions of members accessible to derived classes (that is, protected members).

  • Parameter und Rückgabetypen öffentlicher Methoden von öffentlichen Klassen sowie Parameter und Rückgabetypen von Methoden, auf die abgeleitete Klassen zugreifen können.Parameters and return types of public methods of public classes, and parameters and return types of methods accessible to derived classes.

Die Regeln für CLS-Kompatibilität werden in der folgenden Tabelle aufgeführt.The rules for CLS compliance are listed in the following table. Der Text der Regeln wird in vollem Wortlaut dem ECMA-335-Standard: Common Language Infrastructure entnommen. Copyright 2012 durch Ecma-International.The text of the rules is taken verbatim from the ECMA-335 Standard: Common Language Infrastructure, which is Copyright 2012 by Ecma International. Ausführlichere Informationen zu diesen Regeln finden Sie in den folgenden Abschnitten.More detailed information about these rules is found in the following sections.

KategorieCategory SieheSee RegelRule RegelzahlRule number
BarrierefreiheitAccessibility MemberzugriffMember accessibility Beim Überschreiben von geerbten Methoden darf der Zugriff nicht geändert werden, außer wenn eine Methode überschrieben wird, die von einer anderen Assembly mit family-or-assembly-Zugriff vererbt wurde.Accessibility shall not be changed when overriding inherited methods, except when overriding a method inherited from a different assembly with accessibility family-or-assembly. In diesem Fall muss für die Überschreibung family-Zugriff festgelegt werden.In this case, the override shall have accessibility family. 1010
BarrierefreiheitAccessibility MemberzugriffMember accessibility Die Sichtbarkeit und der Zugriff von Typen und Membern soll so beschaffen sein, dass Typen in der Signatur eines Members sichtbar und zugreifbar sind, wann immer der Member selbst sichtbar und zugreifbar ist.The visibility and accessibility of types and members shall be such that types in the signature of any member shall be visible and accessible whenever the member itself is visible and accessible. Zum Beispiel soll eine öffentliche Methode, die außerhalb der Assembly sichtbar ist, über kein Argument verfügen, dessen Typ nur innerhalb der Assembly sichtbar ist.For example, a public method that is visible outside its assembly shall not have an argument whose type is visible only within the assembly. Die Sichtbarkeit und der Zugriff von Typen, die einen instanziierten generischen Typ zusammensetzen, der in der Signatur eines beliebigen Members verwendet wird, soll sichtbar und zugreifbar sein, wenn der Member selbst sichtbar und zugreifbar ist.The visibility and accessibility of types composing an instantiated generic type used in the signature of any member shall be visible and accessible whenever the member itself is visible and accessible. Zum Beispiel soll ein instanziierter generischer Typ, der in der Signatur eines außerhalb der Assembly sichtbaren Members vorhanden ist, über kein generisches Argument verfügen, dessen Typ nur innerhalb der Assembly sichtbar ist.For example, an instantiated generic type present in the signature of a member that is visible outside its assembly shall not have a generic argument whose type is visible only within the assembly. 1212
ArraysArrays ArraysArrays Arrays müssen über Elemente mit einem CLS-kompatiblen Typ verfügen, und die Untergrenze aller Dimensionen des Arrays muss Null sein.Arrays shall have elements with a CLS-compliant type, and all dimensions of the array shall have lower bounds of zero. Nur der Tatsache, dass es sich bei einem Element um ein Array handelt sowie der Elementtyp des Arrays muss zur Unterscheidung zwischen Überladungen ausreichen.Only the fact that an item is an array and the element type of the array shall be required to distinguish between overloads. Wenn das Überladen auf Grundlage mindestens zweier Arraytypen erfolgt, muss es sich bei den Elementtypen um benannte Typen handeln.When overloading is based on two or more array types the element types shall be named types. 1616
AttributeAttributes AttributeAttributes Attribute müssen vom Typ System.Attribute oder eines davon geerbten Typs sein.Attributes shall be of type System.Attribute, or a type inheriting from it. 4141
AttributeAttributes AttributeAttributes CLS gestattet nur eine Teilmenge der Codierungen benutzerdefinierter Attribute.The CLS only allows a subset of the encodings of custom attributes. Die einzigen in diesen Codierungen zulässigen Typen sind (siehe Partition IV): System.Type, System.String, System.Char, System.Boolean, System.Byte, System.Int16, System.Int32, System.Int64, System.Single, System.Double sowie alle Enumerationstypen, die auf einem CLS-kompatiblen ganzzahligen Basistyp beruhen.The only types that shall appear in these encodings are (see Partition IV): System.Type, System.String, System.Char, System.Boolean, System.Byte, System.Int16, System.Int32, System.Int64, System.Single, System.Double, and any enumeration type based on a CLS-compliant base integer type. 3434
AttributeAttributes AttributeAttributes Nach der CLS sind nicht öffentlich sichtbare erforderliche Modifizierer (modreq, siehe Partition II) zulässig, allerdings sind optionale Modifizierer (modopt, siehe Partition II), die sie nicht versteht, zulässig.The CLS does not allow publicly visible required modifiers (modreq, see Partition II), but does allow optional modifiers (modopt, see Partition II) it does not understand. 3535
KonstruktorenConstructors KonstruktorenConstructors Ein Objektkonstruktor muss einen Instanzenkonstruktor seiner Basisklasse aufrufen, bevor ein Zugriff auf geerbte Instanzdaten erfolgt.An object constructor shall call some instance constructor of its base class before any access occurs to inherited instance data. (Dies gilt nicht für Werttypen, die über keine Konstruktoren verfügen müssen.)(This does not apply to value types, which need not have constructors.) 2121
KonstruktorenConstructors KonstruktorenConstructors Ein Objektkonstruktor darf nicht aufgerufen werden, außer als Teil bei der Erstellung eines Objekts und ein Objekt darf nicht zweimal initialisiert werden.An object constructor shall not be called except as part of the creation of an object, and an object shall not be initialized twice. 2222
EnumerationenEnumerations EnumerationenEnumerations Der zugrunde liegende Typ einer Enumeration muss ein integrierter CLS-Ganzzahltyp sein, der Name des Felds muss "value__" lauten, und das Feld muss als RTSpecialName gekennzeichnet sein.The underlying type of an enum shall be a built-in CLS integer type, the name of the field shall be "value__", and that field shall be marked RTSpecialName. 77
EnumerationenEnumerations EnumerationenEnumerations Es bestehen zwei verschiedene Arten von Enumerationen, die aufgrund des Vorhandenseins oder Fehlens des benutzerdefinierten Attributs System.FlagsAttribute (siehe Partition IV Library) angegeben werden.There are two distinct kinds of enums, indicated by the presence or absence of the System.FlagsAttribute (see Partition IV Library) custom attribute. Eine stellt benannte ganzzahlige Werte dar, die Andere stellt benannte Bitflags dar, die zum Generieren eines unbenannten Werts kombiniert werden können.One represents named integer values; the other represents named bit flags that can be combined to generate an unnamed value. Der Wert einer enum ist nicht auf die angegebenen Werte beschränkt.The value of an enum is not limited to the specified values. 88
EnumerationenEnumerations EnumerationenEnumerations Literale statische Felder einer Enumeration müssen vom Typ der Enumeration selbst sein.Literal static fields of an enum shall have the type of the enum itself. 99
EreignisseEvents EreignisseEvents Die Methoden, die ein Ereignis implementieren, müssen in den Metadaten als SpecialName gekennzeichnet sein.The methods that implement an event shall be marked SpecialName in themetadata. 2929
EreignisseEvents EreignisseEvents Der Zugriff eines Ereignisses und seiner Zugriffsmethoden muss identisch sein.The accessibility of an event and of its accessors shall be identical. 3030
EreignisseEvents EreignisseEvents Die add und remove-Methoden eines Ereignisses müssen entweder beide vorhanden oder beide nicht vorhanden sein.The add and remove methods for an event shall both either be present or absent. 3131
EreignisseEvents EreignisseEvents Die add und remove-Methoden eines Ereignisses müssen jeweils einen Parameter erhalten, dessen Typ den Ereignistyp definiert. Dieser Typ muss von System.Delegate abgeleitet sein.The add and remove methods for an event shall each take one parameter whose type defines the type of the event and that shall be derived from System.Delegate. 3232
EreignisseEvents EreignisseEvents Ereignisse müssen einem bestimmten Benennungsschema folgen.Events shall adhere to a specific naming pattern. Das SpecialName-Attribut, auf das in CLS-Regel 29 verwiesen wird, muss in den entsprechenden Namensvergleichen ignoriert werden und Bezeichnerregeln befolgen.The SpecialName attribute referred to in CLS rule 29 shall be ignored in appropriate name comparisons and shall adhere to identifier rules. 3333
AusnahmenExceptions AusnahmenExceptions Ausgelöste Objekte müssen vom Typ System.Exception oder eines davon geerbten Typs sein.Objects that are thrown shall be of type System.Exception or a type inheriting from it. Dennoch müssen CLS-kompatible Methoden die Weitergabe anderer Ausnahmetypen nicht blockieren.Nonetheless, CLS-compliant methods are not required to block the propagation of other types of exceptions. 4040
AllgemeinGeneral CLS-Kompatibilität: die RegelnCLS compliance: the Rules CLS-Regeln betreffen nur die Teile eines Typs, deren Zugriff oder Sichtbarkeit außerhalb der definierenden Assembly liegen.CLS rules apply only to those parts of a type that are accessible or visible outsideof the defining assembly. 11
AllgemeinGeneral CLS-Kompatibilität: die RegelnCLS compliance: the Rules Member von Typen, die nicht CLS-kompatibel sind, dürfen nicht als CLS-kompatibel gekennzeichnet werden.Members of non-CLS compliant types shall not be marked CLS-compliant. 22
GenerikaGenerics Generische Typen und MemberGeneric types and members Geschachtelte Typen müssen mindestens so viele generische Parameter aufweisen wie der einschließende Typ.Nested types shall have at least as many generic parameters as the enclosing type. Die Position von generischen Parametern in einem geschachtelten Typ entspricht der Position der generischen Parameter im einschließenden Typ.Generic parameters in a nested type correspond by position to the generic parameters in its enclosing type. 4242
GenerikaGenerics Generische Typen und MemberGeneric types and members Der Name eines generischen Typs muss die Anzahl von Typparametern, die auf dem nicht geschachtelten Typ deklariert oder neu in den Typ eingeführt werden, kodieren, wenn er entsprechend der oben definierten Regeln geschachtelt ist.The name of a generic type shall encode the number of type parameters declared on the non-nested type, or newly introduced to the type if nested, according to the rules defined above. 4343
GenerikaGenerics Generische Typen und MemberGeneric types and members Ein generischer Typ muss genügend Einschränkungen neu deklarieren, um zu gewährleisten, dass alle Einschränkungen des Basistyps oder der Schnittstellen durch die Einschränkungen des generischen Typs erfüllt sein würden.A generic type shall redeclare sufficient constraints to guarantee that any constraints on the base type, or interfaces would be satisfied by the generic type constraints. 44444444
GenerikaGenerics Generische Typen und MemberGeneric types and members Als Einschränkungen für generische Parameter verwendete Typen müssen selbst CLS-kompatibel sein.Types used as constraints on generic parameters shall themselves be CLS-compliant. 4545
GenerikaGenerics Generische Typen und MemberGeneric types and members Es muss davon ausgegangen werden, dass die Sichtbarkeit und der Zugriff auf Member (einschließlich geschachtelter Typen) in einem instanziierten generischen Typ sich nicht auf die gesamte Deklaration des generischen Typs bezieht, sondern auf die spezifische Instanziierung.The visibility and accessibility of members (including nested types) in an instantiated generic type shall be considered to be scoped to the specific instantiation rather than the generic type declaration as a whole. Davon ausgehend gelten die Sichtbarkeits- und Zugriffsregeln der CLS-Regel 12 weiterhin.Assuming this, the visibility and accessibility rules of CLS rule 12 still apply. 4646
GenerikaGenerics Generische Typen und MemberGeneric types and members Für jede abstrakte oder virtuell generische Methode muss es eine konkrete (nicht abstrakte) Standardimplementierung geben.For each abstract or virtual generic method, there shall be a default concrete (nonabstract) implementation. 4747
SchnittstellenInterfaces SchnittstellenInterfaces Zum Implementieren von CLS-kompatiblen Schnittstellen darf keine Definition von nicht CLS-kompatiblen Methoden erforderlich sein.CLS-compliant interfaces shall not require the definition of non-CLS compliantmethods in order to implement them. 1818
SchnittstellenInterfaces SchnittstellenInterfaces CLS-kompatible Schnittstellen dürfen weder statische Methoden noch Felder definieren.CLS-compliant interfaces shall not define static methods, nor shall they define fields. 1919
MitgliederMembers Typmember im AllgemeinenType members in general Globale static-Felder und Methoden sind nicht CLS-kompatibel.Global static fields and methods are not CLS-compliant. 3636
MitgliederMembers -- Der Wert eines literalen statischen Elements wird von der Verwendung von Feldinitialisierungsmetadaten angegeben.The value of a literal static is specified through the use of field initialization metadata. Ein CLS-kompatibles Literal muss über einen Wert verfügen, der in den Feldinitialisierungsmetadaten angegeben wird, der genau vom gleichen Typ wie das Literal ist (oder des zugrunde liegenden Typs, wenn dieses Literal enum ist).A CLS-compliant literal must have a value specified in field initialization metadata that is of exactly the same type as the literal (or of the underlying type, if that literal is an enum). 1313
MitgliederMembers Typmember im AllgemeinenType members in general Die vararg-Einschränkung ist nicht Teil der CLS, und die einzige Aufrufkonvention, die von der CLS unterstützt wird, ist die verwaltete Standardaufrufkonvention.The vararg constraint is not part of the CLS, and the only calling convention supported by the CLS is the standard managed calling convention. 1515
Namenskonventionen Naming conventions NamenskonventionenNaming conventions Assemblys müssen Anhang 7 von Fachbericht 15 des Unicode Standard3.0 folgen, in dem der Satz von Zeichen, die in Bezeichnern enthalten sein dürfen geregelt wird. Er ist online unter http://www.unicode.org/unicode/reports/tr15/tr15-18.html verfügbar.Assemblies shall follow Annex 7 of Technical Report 15 of the Unicode Standard3.0 governing the set of characters permitted to start and be included in identifiers, available onlineat http://www.unicode.org/unicode/reports/tr15/tr15-18.html. Bezeichner müssen im kanonischen Format vorliegen, das durch die Unicode-Normalisierungsform C definiert wird. Im Sinne der CLS sind zwei Bezeichner gleich, wenn ihre kleingeschriebenen Zuordnungen (wie von den Gebietsschema-unabhängigen, klein geschriebenen 1:1-Unicodezuordnungen angegeben) gleich sind.Identifiers shall be in thecanonical format defined by Unicode Normalization Form C. For CLS purposes, two identifiersare the same if their lowercase mappings (as specified by the Unicode locale-insensitive, one-toonelowercase mappings) are the same. Demnach müssen sich zwei Bezeichner in mehr als nur der Großschreibung unterscheiden, damit Sie gemäß der CLS als unterschiedlich angesehen werden können.That is, for two identifiers to be considered differentunder the CLS they shall differ in more than simply their case. Um jedoch eine geerbte Definition überschreiben zu können, wird vom CLI die genaue Codierung der ursprünglichen Deklaration erfordert.However, in order to override aninherited definition the CLI requires the precise encoding of the original declaration be used. 44
ÜberladenOverloading NamenskonventionenNaming conventions Alle Namen, die in einem CLS-kompatiblen Bereich eingeführt werden, müssen in ihrer Art eindeutig unabhängig sein, außer bei identischen Namen, die durch Überladen aufgelöst werden.All names introduced in a CLS-compliant scope shall be distinct independent ofkind, except where the names are identical and resolved via overloading. Während es bei CTS möglich ist, dass ein einzelner Typ denselben Namen für eine Methode und ein Feld verwendet, ist dies bei CLS demnach unmöglich.That is, while the CTSallows a single type to use the same name for a method and a field, the CLS does not. 55
ÜberladenOverloading NamenskonventionenNaming conventions Felder und geschachtelte Typen müssen allein durch Vergleich des Bezeichners zu unterscheiden sein, auch wenn bei CTS verschiedene Signaturen unterschieden werden können.Fields and nested types shall be distinct by identifier comparison alone, eventhough the CTS allows distinct signatures to be distinguished. Methoden, Eigenschaften und Ereignisse mit demselben Namen (nach Bezeichnervergleich) müssen sich durch mehr als nur den Rückgabetyp unterscheiden (außer wie in CLS-Regel 39 angegeben).Methods, properties, and eventsthat have the same name (by identifier comparison) shall differ by more than just the return type,except as specified in CLS Rule 39. 66
ÜberladenOverloading ÜberladungenOverloads Nur Eigenschaften und Methoden können überladen werden.Only properties and methods can be overloaded. 3737
ÜberladenOverloading ÜberladungenOverloads Eigenschaften und Methoden können allein basierend auf der Anzahl und den Typen ihrer Parameter überladen werden, außer den Konvertierungsoperatoren op_Implicit und op_Explicit, die auch auf Grundlage des Rückgabetyps überladen werden können.Properties and methods can be overloaded based only on the number and types of their parameters, except the conversion operators named op_Implicit and op_Explicit, which can also be overloaded based on their return type. 3838
ÜberladenOverloading -- Wenn mindestens zwei CLS-kompatible Methoden, die in einem Typ deklariert werden, den gleichen Namen für einen bestimmten Satz von Typinstanziierungen nutzen, und über die gleichen Parameter und Rückgabetypen verfügen, dann müssen alle diese Methoden an diesen Typinstanziierungen semantisch gleichwertig sein.If two or more CLS-compliant methods declared in a type have the same nameand, for a specific set of type instantiations, they have the same parameter and return types, thenall these methods shall be semantically equivalent at those type instantiations. 4848
TypenTypes Typ und TypmembersignaturenType and type member signatures System.Object ist CLS-kompatibel.System.Object is CLS-compliant. Jede andere CLS-kompatible Klasse muss von einer CLS-kompatiblen Klasse erben.Any other CLS-compliant class shall inherit from a CLS-compliant class. 2323
EigenschaftenProperties EigenschaftenProperties Die Methoden, mit denen die Getter-Methode und die Setter-Methode einer Eigenschaft implementiert werden, müssen in den Metadaten mit SpecialName markiert werden.The methods that implement the getter and setter methods of a property shallbe marked SpecialName in the metadata. 2424
EigenschaftenProperties EigenschaftenProperties Die Zugriffsmethoden einer Eigenschaft müssen alle „static“, alle „virtual“ oder alle „instance“ sein.A property’s accessors shall all be static, all be virtual, or all be instance. 2626
EigenschaftenProperties EigenschaftenProperties Der Typ einer Eigenschaft muss dem Rückgabetyp der Getter-Methode und dem Typ des letzten Arguments der Setter-Methode entsprechen.The type of a property shall be the return type of the getter and the type of the last argument of the setter. Die Parametertypen der Eigenschaft müssen den Parametertypen der Getter-Methode und, ausgenommen dem Letzten, allen Parametertypen der Setter-Methode entsprechen.The types of the parameters of the property shall be the types of the parameters to the getter and the types of all but the final parameter of the setter. Diese Typen müssen CLS-kompatibel sein und dürfen keine verwalteten Zeiger sein (d. h., sie dürfen nicht als Verweise übergeben werden).All of these types shall be CLS-compliant, and shall not be managed pointers (i.e., shall not be passed by reference). 2727
EigenschaftenProperties EigenschaftenProperties Eigenschaften müssen einem bestimmten Benennungsschema folgen.Properties shall adhere to a specific naming pattern. Das SpecialName-Attribut, auf das in CLS-Regel 24 verwiesen wird, muss in den entsprechenden Namensvergleichen ignoriert werden und Bezeichnerregeln einhalten.The SpecialName attribute referred to in CLS rule 24 shall be ignored in appropriate name comparisons and shall adhere to identifier rules. Eine Eigenschaft verfügt über eine Getter-Methode, eine Setter-Methode oder beide.A property shall have a getter method, a setter method, or both. 2828
TypkonvertierungType conversion TypkonvertierungType conversion Wenn entweder op_Implicit oder op_Explicit bereitgestellt werden, muss eine alternative Möglichkeit für die Umwandlung bereitgestellt werden.If either op_Implicit or op_Explicit is provided, an alternate means of providing the coercion shall be provided. 3939
TypenTypes Typ und TypmembersignaturenType and type member signatures Geschachtelte Werttypen sind nicht CLS-kompatibel.Boxed value types are not CLS-compliant. 33
TypenTypes Typ und TypmembersignaturenType and type member signatures Alle Typen, die in einer Signatur erscheinen, müssen CLS-kompatibel sein.All types appearing in a signature shall be CLS-compliant. Alle Typen, die einen instanziierten generischen Typ erstellen, müssen CLS-kompatibel sein.All types composing an instantiated generic type shall be CLS-compliant. 1111
TypenTypes Typ und TypmembersignaturenType and type member signatures Typisierte Verweise sind nicht CLS-kompatibel.Typed references are not CLS-compliant. 1414
TypenTypes Typ und TypmembersignaturenType and type member signatures Nicht verwaltete Zeigertypen sind nicht CLS-kompatibel.Unmanaged pointer types are not CLS-compliant. 1717
TypenTypes Typ und TypmembersignaturenType and type member signatures CLS-kompatible Klassen, Werttypen und Schnittstellen dürfen die Implementierung von nicht CLS-kompatiblen Membern nicht erfordern.CLS-compliant classes, value types, and interfaces shall not require the implementation of non-CLS-compliant members. 2020

Typen und TypmembersignaturenTypes and type member signatures

Der System.Object-Typ ist CLS-kompatibel, und er ist der Basistyp aller Objekttypen im .NET Framework-Typsystem.The System.Object type is CLS-compliant and is the base type of all object types in the .NET Framework type system. Vererbung erfolgt im .NET Framework entweder implizit (zum Beispiel erbt die String-Klasse implizit von der Object-Klasse) oder explizit (zum Beispiel erbt die CultureNotFoundException-Klasse explizit von der ArgumentException-Klasse, die explizit von der SystemException-Klasse erbt, die explizit von der Exception-Klasse erbt).Inheritance in the .NET Framework is either implicit (for example, the String class implicitly inherits from the Object class) or explicit (for example, the CultureNotFoundException class explicitly inherits from the ArgumentException class, which explicitly inherits from the SystemException class, which explicitly inherits from the Exception class). Damit ein abgeleiteter Typ CLS-kompatibel ist, muss auch der Basistyp CLS-kompatibel sein.For a derived type to be CLS compliant, its base type must also be CLS-compliant.

Im folgenden Beispiel wird ein abgeleiteter Typ veranschaulicht, dessen Basistyp nicht CLS-kompatibel ist.The following example shows a derived type whose base type is not CLS-compliant. Es wird eine Counter-Basisklasse definiert, die eine ganze Zahl ohne Vorzeichen mit einer Länge von 32 Bit als Indikator verwendet.It defines a base Counter class that uses an unsigned 32-bit integer as a counter. Da die Klasse Gegenfunktionalität bereitstellt, indem eine ganze Zahl ohne Vorzeichen umgebrochen wird, wird die Klasse als nicht CLS-kompatibel gekennzeichnet.Because the class provides counter functionality by wrapping an unsigned integer, the class is marked as non-CLS-compliant. Daher ist eine abgeleitete Klasse, NonZeroCounter, auch nicht CLS-kompatibel.As a result, a derived class, NonZeroCounter, is also not CLS-compliant.

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
'                 ~~~~~~~~~~~~~~

Alle in den Membersignaturen angezeigten Typen, einschließlich des Rückgabetyps oder des Eigenschaftentyps einer Methode, müssen CLS-kompatibel sein.All types that appear in member signatures, including a method's return type or a property type, must be CLS-compliant. Außerdem ist für generische Typen Folgendes erforderlich:In addition, for generic types:

  • Alle Typen, die einen instanziierten generischen Typ zusammensetzen, müssen CLS-kompatibel sein.All types that compose an instantiated generic type must be CLS-compliant.

  • Alle als Einschränkungen für generische Parameter verwendeten Typen müssen CLS-kompatibel sein.All types used as constraints on generic parameters must be CLS-compliant.

Das allgemeine Typsystem von .NET Framework enthält verschiedene integrierte Datentypen, die direkt von der Common Language Runtime unterstützt werden und insbesondere in den Metadaten einer Assembly codiert werden.The .NET Framework common type system includes a number of built-in types that are supported directly by the common language runtime and are specially encoded in an assembly's metadata. Von diesen systeminternen Typen sind die in der folgenden Tabelle aufgeführten Typen CLS-kompatibel.Of these intrinsic types, the types listed in the following table are CLS-compliant.

CLS-kompatibler TypCLS-compliant type BeschreibungDescription
Byte Ganze 8-Bit-Zahl ohne Vorzeichen8-bit unsigned integer
Int16 Ganze 16-Bit-Zahl mit Vorzeichen16-bit signed integer
Int32 32-Bit-Ganzzahl mit Vorzeichen32-bit signed integer
Int64 64-Bit-Ganzzahl mit Vorzeichen64-bit signed integer
Single Gleitkommawert mit einfacher GenauigkeitSingle-precision floating-point value
Double Gleitkommawert mit doppelter GenauigkeitDouble-precision floating-point value
Boolean true oder false value_typetrue or false value type
Char UTF-16-codierte CodeeinheitUTF-16 encoded code unit
Decimal Dezimalzahl ohne GleitkommaNon-floating-point decimal number
IntPtr Zeiger oder Handle einer Plattform-definierten GrößePointer or handle of a platform-defined size
String Auflistung von keinem, einem oder mehreren Char-ObjektenCollection of zero, one, or more Char objects

Die in der folgenden Tabelle aufgeführten systeminternen Typen sind nicht CLS-kompatibel.The intrinsic types listed in the following table are not CLS-Compliant.

Nicht kompatibler TypNon-compliant type BeschreibungDescription CLS-kompatible AlternativeCLS-compliant alternative
SByte Ganzzahliger 8-Bit-Datentyp mit Vorzeichen8-bit signed integer data type Int16
TypedReference Zeiger auf ein Objekt und den LaufzeittypPointer to an object and its runtime type KeineNone
UInt16 16-Bit-Ganzzahl ohne Vorzeichen16-bit unsigned integer Int32
UInt32 32-Bit-Ganzzahl ohne Vorzeichen32-bit unsigned integer Int64
UInt64 64-Bit-Ganzzahl ohne Vorzeichen64-bit unsigned integer Int64 (kann überlaufen), BigInteger oder DoubleInt64 (may overflow), BigInteger, or Double
UIntPtr Zeiger ohne Vorzeichen oder HandleUnsigned pointer or handle IntPtr

Die .NET Framework-Klassenbibliothek oder jede andere Klassenbibliothek schließen möglicherweise andere nicht CLS-kompatible Typen ein, zum Beispiel:The .NET Framework Class Library or any other class library may include other types that aren't CLS-compliant; for example:

  • Geschachtelte WerttypenBoxed value types. Im folgenden C#-Beispiel wird eine Klasse erstellt, die über eine öffentliche Eigenschaft des Typs int* namens Value verfügt.The following C# example creates a class that has a public property of type int* named Value. Da int* ein geschachtelter Werttyp ist, markiert der Compiler ihn als nicht CLS-kompatibel.Because an int* is a boxed value type, the compiler flags it as non-CLS-compliant.

    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
    
  • Typisierte Verweise, die spezielle Konstrukte sind, in denen ein Verweis auf ein Objekt und ein Verweis auf einen Typ enthalten sind.Typed references, which are special constructs that contain a reference to an object and a reference to a type. Typisierte Verweise werden in .NET Framework von der TypedReference-Klasse dargestellt.Typed references are represented in the .NET Framework by the TypedReference class.

Wenn ein Typ nicht CLS-kompatibel ist, sollten Sie das CLSCompliantAttribute-Attribut mit einem Wert von isCompliant``false darauf anwenden.If a type is not CLS-compliant, you should apply the CLSCompliantAttribute attribute with an isCompliant value of false to it. Weitere Informationen finden Sie im Abschnitt Das CLSCompliantAttribute-Attribut.For more information, see the The CLSCompliantAttribute attribute section.

Im folgenden Beispiel wird das Problem der CLS-Kompatibilität in einer Methodensignatur und in der Instanziierung des generischen Typs veranschaulicht.The following example illustrates the problem of CLS compliance in a method signature and in generic type instantiation. Dabei wird eine InvoiceItem-Klasse mit einer Eigenschaft vom Typ UInt32, einer Eigenschaft vom Typ Nullable(Of UInt32) und einem Konstruktor mit Parametern vom Typ UInt32 sowie Nullable(Of UInt32) definiert.It defines an InvoiceItem class with a property of type UInt32, a property of type Nullable(Of UInt32), and a constructor with parameters of type UInt32 and Nullable(Of UInt32). Sie erhalten vier Compilerwarnungen, wenn Sie versuchen, das Beispiel zu kompilieren.You get four compiler warnings when you try to compile this example.

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
'                       ~~~~~~~~~

Um die Compilerwarnungen auszuschließen, ersetzen Sie die nicht CLS-kompatiblen Typen in der öffentlichen InvoiceItem-Schnittstelle durch kompatible Typen:To eliminate the compiler warnings, replace the non-CLS-compliant types in the InvoiceItem public interface with compliant types:

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

Zusätzlich zu bestimmten aufgeführten Typen sind einige Typenkategorien ebenfalls nicht CLS-kompatibel.In addition to the specific types listed, some categories of types are not CLS compliant. Diese schließen nicht verwaltete Zeigertypen und Funktionszeigertypen ein.These include unmanaged pointer types and function pointer types. Im folgenden Beispiel wird eine Compilerwarnung erzeugt, da ein Zeiger auf eine ganze Zahl verwendet wird, um ein Array ganzer Zahlen zu erstellen.The following example generates a compiler warning because it uses a pointer to an integer to create an array of integers.

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

Für CLS-kompatible abstrakte Klassen (das heißt, Klassen, die als abstract in C# oder als MustInherit in Visual Basic markiert sind), müssen alle Member der Klasse auch CLS-kompatibel sein.For CLS-compliant abstract classes (that is, classes marked as abstract in C# or as MustInherit in Visual Basic), all members of the class must also be CLS-compliant.

Namenskonventionen Naming conventions

Da bei einigen Programmiersprachen die Groß- und Kleinschreibung nicht beachtet werden muss, müssen Bezeichner (wie die Namen von Namespaces, Typen und Membern) durch mehr als die Groß-/Kleinschreibung unterschieden werden.Because some programming languages are case-insensitive, identifiers (such as the names of namespaces, types, and members) must differ by more than case. Zwei Bezeichner gelten als äquivalent, wenn ihre kleingeschriebenen Zuordnungen identisch sind.Two identifiers are considered equivalent if their lowercase mappings are the same. Im folgenden C#-Beispiel werden zwei öffentliche Klassen definiert: Person und person.The following C# example defines two public classes, Person and person. Da sie sich nur durch die Groß-/Kleinschreibung unterscheiden, markiert der C#-Compiler sie als nicht CLS-kompatibel.Because they differ only by case, the C# compiler flags them as not CLS-compliant.

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)

Programmiersprachenbezeichner, wie die Namen von Namespaces, Typen und Membern, müssen dem Unicode-Standard 3.0, Fachbericht 15, Anhang 7 entsprechen.Programming language identifiers, such as the names of namespaces, types, and members, must conform to the Unicode Standard 3.0, Technical Report 15, Annex 7. Dies bedeutet Folgendes:This means that:

  • Das erste Zeichen eines Bezeichners kann jeder Unicode-Großbuchstabe, Kleinbuchstabe, großer Anfangsbuchstabe, Modifiziererbuchstabe, anderer Buchstabe oder jede Buchstabenzahl sein.The first character of an identifier can be any Unicode uppercase letter, lowercase letter, title case letter, modifier letter, other letter, or letter number. Informationen zu Unicode-Zeichenkategorien finden Sie unter der System.Globalization.UnicodeCategory-Enumeration.For information on Unicode character categories, see the System.Globalization.UnicodeCategory enumeration.

  • Nachfolgende Zeichen können aus einer der Kategorien wie das erste Zeichen stammen, und sie können auch Markierungen ohne Zwischenraum, Sperrmarkierungen, Dezimalwerte, Connectorinterpunktionen und Formatierungscodes umfassen.Subsequent characters can be from any of the categories as the first character, and can also include non-spacing marks, spacing combining marks, decimal numbers, connector punctuations, and formatting codes.

Bevor Sie Bezeichner vergleichen, sollten Sie Formatierungscodes herausfiltern und die Bezeichner in die Unicode-Normalisierungsform C konvertieren, da ein einzelnes Zeichen durch mehrere UTF-16-codierte Codeeinheiten dargestellt werden kann.Before you compare identifiers, you should filter out formatting codes and convert the identifiers to Unicode Normalization Form C, because a single character can be represented by multiple UTF-16-encoded code units. Zeichensequenzen, die die gleichen Codeeinheiten in der Unicode-Normalisierungsform C erzeugen, sind nicht CLS-kompatibel.Character sequences that produce the same code units in Unicode Normalization Form C are not CLS-compliant. Im folgenden Beispiel werden zwei Eigenschaften definiert: eine namens , die aus dem Zeichen ÅNGSTRÖM-ZEICHEN (U+212B) besteht, und eine zweite namens Å, die aus dem Zeichen LATEINISCHER GROSSBUCHSTABE A MIT RING OBEN (U+00C5) besteht.The following example defines a property named , which consists of the character ANGSTROM SIGN (U+212B), and a second property named Å, which consists of the character LATIN CAPITAL LETTER A WITH RING ABOVE (U+00C5). Die Compiler von C#- und Visual Basic kennzeichnen den Quellcode als nicht CLS-kompatibel.Both the C# and Visual Basic compilers flag the source code as non-CLS-compliant.

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
'                       ~

Membernamen innerhalb eines bestimmten Bereichs (wie den Namespaces innerhalb einer Assembly, den Typen in einem Namespace oder den Membern innerhalb eines Typs) müssen eindeutig sein, abgesehen von Namen, die durch Überladen aufgelöst werden.Member names within a particular scope (such as the namespaces within an assembly, the types within a namespace, or the members within a type) must be unique except for names that are resolved through overloading. Diese Anforderung ist zwingender als die des allgemeinen Typsystems, bei dem mehrere Member innerhalb eines Bereichs über identische Namen verfügen dürfen, solange es unterschiedliche Arten von Membern sind (zum Beispiel eine Methode und ein Feld).This requirement is more stringent than that of the common type system, which allows multiple members within a scope to have identical names as long as they are different kinds of members (for example, one is a method and one is a field). Insbesondere für Typmember:In particular, for type members:

  • Felder und geschachtelte Typen werden allein nach Namen unterschieden.Fields and nested types are distinguished by name alone.

  • Methoden, Eigenschaften und Ereignisse mit demselben Namen müssen sich durch mehr als nur den Rückgabetyp unterscheiden.Methods, properties, and events that have the same name must differ by more than just return type.

Im folgenden Beispiel wird die Anforderung veranschaulicht, dass Membernamen innerhalb des Bereichs eindeutig sein müssen.The following example illustrates the requirement that member names must be unique within their scope. Es wird eine Klasse namens Converter definiert, die vier Member namens Conversion umfasst.It defines a class named Converter that includes four members named Conversion. Drei Methoden und eine Eigenschaft.Three are methods, and one is a property. Die Methode, die einen Parameter Int64 umfasst, hat einen eindeutigen Namen, doch die beiden Methoden mit einem Int32-Parameter sind nicht eindeutig, da der Rückgabewert nicht als ein Teil der Signatur eines Members gültig ist.The method that includes an Int64 parameter is uniquely named, but the two methods with an Int32 parameter are not, because return value is not considered a part of a member's signature. Die Conversion- Eigenschaft verstößt auch gegen diese Anforderung, da Eigenschaften nicht den gleichen Namen wie überladene Methoden besitzen dürfen.The Conversion property also violates this requirement, because properties cannot have the same name as overloaded methods.

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
'                                ~~~~~~~~~~

Einzelne Sprachen enthalten eindeutige Schlüsselwörter, sodass Sprachen für die Common Language Runtime einen Mechanismus zum Verweisen auf Bezeichner (z. B. Typnamen) bereitstellen müssen, die mit den Schlüsselwörtern übereinstimmen.Individual languages include unique keywords, so languages that target the common language runtime must also provide some mechanism for referencing identifiers (such as type names) that coincide with keywords. Beispielsweise ist case ein Schlüsselwort in C# und Visual Basic.For example, case is a keyword in both C# and Visual Basic. Im folgenden Visual Basic-Beispiel wird eine Klasse namens case eindeutig vom case-Schlüsselwort unterschieden, indem öffnende und schließende geschweifte Klammern verwendet werden.However, the following Visual Basic example is able to disambiguate a class named case from the case keyword by using opening and closing braces. Andernfalls würde in dem Beispiel die folgende Fehlermeldung erzeugt: "Das Schlüsselwort ist kein gültiger Bezeichner", und der Code könnte nicht kompiliert werden.Otherwise, the example would produce the error message, "Keyword is not valid as an identifier," and fail to compile.

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

Im folgenden C#-Beispiel kann die case-Klasse instanziiert werden, indem das @ Symbol verwendet wird, um den Bezeichner eindeutig vom Schlüsselwort zu unterscheiden.The following C# example is able to instantiate the case class by using the @ symbol to disambiguate the identifier from the language keyword. Ohne dieses Zeichen würde der C#-Compiler zwei Fehlermeldungen anzeigen:"Typ erwartet" und "Ungültiger Ausdruck 'case'".Without it, the C# compiler would display two error messages, "Type expected" and "Invalid expression term 'case'."

using System;

public class Example
{
   public static void Main()
   {
      @case c = new @case("John");
      Console.WriteLine(c.ClientName);
   }
}

TypkonvertierungType conversion

In der Common Language Specification werden zwei Konvertierungsoperatoren definiert:The Common Language Specification defines two conversion operators:

  • op_Implicit, das für Erweiterungskonvertierungen verwendet wird, die zu keinem Datenverlust oder Genauigkeitsverlust führen.op_Implicit, which is used for widening conversions that do not result in loss of data or precision. Zum Beispiel umfasst die Decimal-Struktur einen überladenen op_Implicit-Operator, um Werte ganzzahliger Typen und Char-Werte in Decimal-Werte zu konvertieren.For example, the Decimal structure includes an overloaded op_Implicit operator to convert values of integral types and Char values to Decimal values.

  • op_Explicit, der für einschränkende Konvertierungen verwendet wird, die zu Größenverlusten (ein Wert wird in einen Wert konvertiert, der über einen kleineren Bereich verfügt) bzw. zu Verlusten der Genauigkeit führen können.op_Explicit, which is used for narrowing conversions that can result in loss of magnitude (a value is converted to a value that has a smaller range) or precision. Zum Beispiel umfasst die Decimal-Struktur einen überladenen op_Explicit-Operator, um den Double-Wert und den Single-Wert in Decimal zu konvertieren und die Decimal-Werte in die ganzzahligen Werte Double, Single und Char zu konvertieren.For example, the Decimal structure includes an overloaded op_Explicit operator to convert Double and Single values to Decimal and to convert Decimal values to integral values, Double, Single, and Char.

Allerdings wird Operatorüberladung oder die Definition benutzerdefinierter Operatoren nicht von allen Sprachen unterstützt.However, not all languages support operator overloading or the definition of custom operators. Wenn Sie diese Konvertierungsoperatoren implementieren, sollten Sie eine alternative Methode zum Ausführen der Konvertierung bereitstellen.If you choose to implement these conversion operators, you should also provide an alternate way to perform the conversion. Es wird empfohlen, FromXxx- und ToXxx-Methoden bereitzustellen.We recommend that you provide FromXxx and ToXxx methods.

Im folgenden Beispiel werden CLS-kompatible implizite und explizite Konvertierungen definiert.The following example defines CLS-compliant implicit and explicit conversions. Es wird eine UDouble-Klasse erstellt, die eine Gleitkommazahl mit doppelter Genauigkeit und Vorzeichen darstellt.It creates a UDouble class that represents an signed double-precision, floating-point number. Implizite Konvertierungen aus UDouble in Double und explizite Konvertierungen aus UDouble in Single, aus Double in UDouble und aus Single in UDouble werden bereitgestellt.It provides for implicit conversions from UDouble to Double and for explicit conversions from UDouble to Single, Double to UDouble, and Single to UDouble. Es wird auch eine ToDouble-Methode als Alternative zum Operator für implizite Konvertierung definiert, und die ToSingle, FromDouble-Methode sowie die FromSingle-Methode werden als Alternativen zu den Operatoren der expliziten Konvertierung definiert.It also defines a ToDouble method as an alternative to the implicit conversion operator and the ToSingle, FromDouble, and FromSingle methods as alternatives to the explicit conversion operators.

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

ArraysArrays

CLS-kompatible Arrays sind mit den folgenden Regeln kompatibel:CLS-compliant arrays conform to the following rules:

  • Die unteren Begrenzungen aller Dimensionen eines Arrays müssen gleich 0 sein.All dimensions of an array must have a lower bound of zero. Im folgenden Beispiel wird ein Array mit einer nicht CLS-kompatiblen Untergrenze von eins erstellt.The following example creates a non-CLS-compliant array with a lower bound of one. Beachten Sie, dass vom Compiler ungeachtet des Vorhandenseins des CLSCompliantAttribute-Attributs nicht erkannt wird, dass das von der Numbers.GetTenPrimes-Methode zurückgegebene Array nicht CLS-kompatibel ist.Note that, despite the presence of the CLSCompliantAttribute attribute, the compiler does not detect that the array returned by the Numbers.GetTenPrimes method is not CLS-compliant.

    [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
    
  • Alle Arrayelemente müssen aus CLS-kompatiblen Typen bestehen.All array elements must consist of CLS-compliant types. Im folgenden Beispiel werden zwei Methoden, die nicht CLS-kompatible Arrays zurückgeben, definiert.The following example defines two methods that return non-CLS-compliant arrays. Die erste Methode gibt ein Array von UInt32-Werten zurück.The first returns an array of UInt32 values. Die zweite Methode gibt ein Object-Array zurück, das den Int32-Wert und den UInt32-Wert umfasst.The second returns an Object array that includes Int32 and UInt32 values. Obwohl der Compiler das erste Array aufgrund des UInt32-Typs als nicht kompatibel identifiziert, wird nicht erkannt, dass das zweite Array nicht CLS-kompatible Elemente umfasst.Although the compiler identifies the first array as non-compliant because of its UInt32 type, it fails to recognize that the second array includes non-CLS-compliant elements.

    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()
    '                              ~~~~~~~~~~~~
    
  • Die Überladungsauflösung für Methoden mit Arrayparametern basiert sowohl auf der Tatsache, dass es Arrays sind, als auch auf dem Elementtyp.Overload resolution for methods that have array parameters is based on the fact that they are arrays and on their element type. Aus diesem Grund ist die folgende Definition einer überladenen GetSquares-Methode CLS-kompatibel.For this reason, the following definition of an overloaded GetSquares method is CLS-compliant.

    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
    

SchnittstellenInterfaces

CLS-kompatible Schnittstellen können Eigenschaften, Ereignisse und virtuelle Methoden (Methoden ohne Implementierung) definieren.CLS-compliant interfaces can define properties, events, and virtual methods (methods with no implementation). Eine CLS-kompatible Schnittstelle kann keine der folgenden Aspekte aufweisen:A CLS-compliant interface cannot have any of the following:

  • Statische Methoden oder statische FelderStatic methods or static fields. Der C#- und der Visual Basic-Compiler erstellen Compilerfehler, wenn Sie einen statischen Member in einer Schnittstelle definieren.Both the C# and Visual Basic compilers generate compiler errors if you define a static member in an interface.

  • FelderFields. Die Compiler von C# und Visual Basic generieren Compilerfehler, wenn Sie ein Feld in einer Schnittstelle definieren.Both the C# and Visual Basic compilers generate compiler errors if you define a field in an interface.

  • Methoden, die nicht CLS-kompatibel sind.Methods that are not CLS-compliant. Zum Beispiel umfasst die folgende Schnittstellendefinition eine Methode, INumber.GetUnsigned, die als nicht CLS-kompatibel gekennzeichnet wird.For example, the following interface definition includes a method, INumber.GetUnsigned, that is marked as non-CLS-compliant. In diesem Beispiel wird eine Compilerwarnung generiert.This example generates a compiler warning.

    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
    '                                      ~~~~~~~~~~~
    

    Aufgrund dieser Regel, ist es nicht erforderlich, dass CLS-kompatible Typen nicht CLS-kompatible Member implementieren.Because of this rule, CLS-compliant types are not required to implement non-CLS-compliant members. Wenn ein CLS-kompatibles Framework eine Klasse verfügbar macht, die eine nicht CLS- kompatible Schnittstelle implementiert, sollte sie konkrete Implementierungen aller nicht-CLS-kompatiblen Member angeben.If a CLS-compliant framework does expose a class that implements a non-CLS compliant interface, it should also provide concrete implementations of all non-CLS-compliant members.

CLS-kompatible Sprachcompiler müssen einer Klasse auch ermöglichen, separate Implementierungen von Membern bereitzustellen, die in mehreren Schnittstellen über den gleichen Namen und dieselbe Signatur verfügen.CLS-compliant language compilers must also allow a class to provide separate implementations of members that have the same name and signature in multiple interfaces. C# und Visual Basic unterstützen explizite Schnittstellenimplementierungen, um unterschiedliche Implementierungen identisch benannter Methoden bereitzustellen.Both C# and Visual Basic support explicit interface implementations to provide different implementations of identically named methods. Visual Basic unterstützt darüber hinaus das Implements-Schlüsselwort, mit dem Sie explizit festlegen können, welche Schnittstelle und welcher Member von einem bestimmten Member implementiert werden.Visual Basic also supports the Implements keyword, which enables you to explicitly designate which interface and member a particular member implements. Im folgenden Beispiel wird dieses Szenario veranschaulicht, indem eine Temperature-Klasse definiert wird, die die ICelsius-Schnittstelle und die IFahrenheit-Schnittstelle als explizite Schnittstellenimplementierungen implementiert.The following example illustrates this scenario by defining a Temperature class that implements the ICelsius and IFahrenheit interfaces as explicit interface implementations.

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

EnumerationenEnumerations

Bei CLS-kompatiblen Enumerationen müssen die folgenden Regeln beachtet werden:CLS-compliant enumerations must follow these rules:

  • Der zugrunde liegende Typ der Enumeration muss ein systeminterner CLS-kompatibler Ganzzahltyp sein (Byte, Int16, Int32 oder Int64).The underlying type of the enumeration must be an intrinsic CLS-compliant integer (Byte, Int16, Int32, or Int64). Im folgenden Code wird beispielsweise versucht, eine Enumeration zu definieren, deren zugrunde liegender Typ UInt32 ist. Es wird eine Compilerwarnung generiert.For example, the following code tries to define an enumeration whose underlying type is UInt32 and generates a compiler warning.

    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
    '                ~~~~
    
  • Ein Enumerationstyp muss über ein Feld namens Value__ mit einer einzelnen Instanz verfügen, das mit dem FieldAttributes.RTSpecialName-Attribut markiert ist.An enumeration type must have a single instance field named Value__ that is marked with the FieldAttributes.RTSpecialName attribute. Damit können Sie den Feldwert implizit verweisen.This enables you to reference the field value implicitly.

  • Eine Enumeration umfasst literale statische Felder, deren Typen vom gleichen Typ wie die Enumeration selbst sein müssen.An enumeration includes literal static fields whose types match the type of the enumeration itself. Wenn Sie zum Beispiel eine State-Enumeration mit den Werten aus State.On und State.Off definieren, sind State.On und State.Off literale statische Felder, deren Typ State ist.For example, if you define a State enumeration with values of State.On and State.Off, State.On and State.Off are both literal static fields whose type is State.

  • Es gibt zwei Arten von Enumerationen.There are two kinds of enumerations:

    • Eine Enumeration, die einen Satz wechselseitig exklusiver, benannter ganzzahliger Werte darstellt.An enumeration that represents a set of mutually exclusive, named integer values. Dieser Typ der Enumeration wird durch das Fehlen des benutzerdefinierten System.FlagsAttribute-Attributs angegeben.This type of enumeration is indicated by the absence of the System.FlagsAttribute custom attribute.

    • Eine Enumeration, die einen Satz von Bitflags darstellt, die zum Generieren eines unbenannten Werts kombiniert werden können.An enumeration that represents a set of bit flags that can combine to generate an unnamed value. Dieser Typ der Enumeration wird durch das Vorhandensein des benutzerdefinierten System.FlagsAttribute-Attributs angegeben.This type of enumeration is indicated by the presence of the System.FlagsAttribute custom attribute.

    Weitere Informationen finden Sie in der Dokumentation zur Enum-Struktur.For more information, see the documentation for the Enum structure.

  • Der Wert einer Enumeration wird nicht auf den Bereich der angegebenen Werte beschränkt.The value of an enumeration is not limited to the range of its specified values. Das heißt, der Wertebereich einer Enumeration ist der Bereich des zugrunde liegenden Werts.In other words, the range of values in an enumeration is the range of its underlying value. Sie können die Enum.IsDefined-Methode verwenden, um zu bestimmen, ob ein angegebener Wert ein Member einer Enumeration ist.You can use the Enum.IsDefined method to determine whether a specified value is a member of an enumeration.

Typmember im AllgemeinenType members in general

Die Common Language Specification erfordert, dass auf alle Felder und Methoden als Member einer bestimmten Klasse zugegriffen werden.The Common Language Specification requires all fields and methods to be accessed as members of a particular class. Daher sind globale statische Felder und Methoden (das heißt, statische Felder oder Methoden, die unabhängig von einem Typ definiert werden), nicht CLS-kompatibel.Therefore, global static fields and methods (that is, static fields or methods that are defined apart from a type) are not CLS-compliant. Wenn Sie versuchen, ein globales Feld oder eine Methode im Quellcode einzuschließen, wird vom C#-Compiler und vom Visual Basic-Compiler ein Compilerfehler generiert.If you try to include a global field or method in your source code, both the C# and Visual Basic compilers generate a compiler error.

Die Common Language Specification unterstützt nur die verwaltete Standardaufrufkonvention.The Common Language Specification supports only the standard managed calling convention. Sie unterstützt keine nicht verwalteten Aufrufkonventionen und keine Methoden mit variablen Argumentlisten, die mit dem varargs-Schlüsselwort gekennzeichnet werden.It doesn't support unmanaged calling conventions and methods with variable argument lists marked with the varargs keyword. Verwenden Sie für Variablenargumentlisten, die mit der verwalteten Standardaufrufkonvention kompatibel sind, das ParamArrayAttribute-Attribut oder die einzelne Implementierung der Sprache, wie z. B. das params-Schlüsselwort in C# und das ParamArray-Schlüsselwort in Visual Basic.For variable argument lists that are compatible with the standard managed calling convention, use the ParamArrayAttribute attribute or the individual language's implementation, such as the params keyword in C# and the ParamArray keyword in Visual Basic.

MemberzugriffMember accessibility

Das Überschreiben eines geerbten Members kann den Zugriff auf diesen Member nicht ändern.Overriding an inherited member cannot change the accessibility of that member. Beispielsweise kann eine öffentliche Methode in einer Basisklasse nicht von einer privaten Methode in einer abgeleiteten Klasse überschrieben werden.For example, a public method in a base class cannot be overridden by a private method in a derived class. Es gibt allerdings eine Ausnahme: einen protected internal-Member (in C#) oder einen Protected Friend-Member (in Visual Basic) in einer Assembly, die von einem Typ in einer anderen Assembly überschrieben wird.There is one exception: a protected internal (in C#) or Protected Friend (in Visual Basic) member in one assembly that is overridden by a type in a different assembly. In diesem Fall ist der Zugriff auf die Überschreibung Protected.In that case, the accessibility of the override is Protected.

Im folgenden Beispiel wird der Fehler veranschaulicht, der generiert wird, wenn das CLSCompliantAttribute-Attribut auf true festgelegt wird und Person , eine von Animal abgeleitete Klasse, versucht den Zugriff auf die Species-Eigenschaft von öffentlich auf privat zu ändern.The following example illustrates the error that is generated when the CLSCompliantAttribute attribute is set to true, and Person, which is a class derived from Animal, tries to change the accessibility of the Species property from public to private. Das Beispiel wird erfolgreich kompiliert, wenn der Zugriff auf öffentlich geändert wird.The example compiles successfully if its accessibility is changed to public.

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

Der Zugriff auf Typen in der Signatur eines Members muss möglich sein, wenn auf den Member zugegriffen werden kann.Types in the signature of a member must be accessible whenever that member is accessible. Das bedeutet zum Beispiel, dass ein öffentlicher Member keinen Parameter enthalten kann, dessen Typ privat, geschützt oder intern ist.For example, this means that a public member cannot include a parameter whose type is private, protected, or internal. Im folgenden Beispiel wird der Compilerfehler veranschaulicht, der entsteht, wenn ein StringWrapper-Klassenkonstruktor einen internen StringOperationType-Enumerationswert verfügbar macht, der bestimmt, wie ein Zeichenfolgenwert umschlossen werden soll.The following example illustrates the compiler error that results when a StringWrapper class constructor exposes an internal StringOperationType enumeration value that determines how a string value should be wrapped.

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)
'                              ~~~~~~~~~~~~~~~~~~~

Generische Typen und MemberGeneric types and members

Geschachtelte Typen weisen immer mindestens so viele generische Parameter auf wie der einschließende Typ.Nested types always have at least as many generic parameters as their enclosing type. Diese entsprechen der Position nach den generischen Parametern im einschließenden Typ.These correspond by position to the generic parameters in the enclosing type. Der generische Typ kann auch neue generische Parameter enthalten.The generic type can also include new generic parameters.

Die Beziehung zwischen generischen Typparametern eines enthaltenden Typs und den geschachtelten Typen wird möglicherweise von der Syntax der einzelnen Sprachen verdeckt.The relationship between the generic type parameters of a containing type and its nested types may be hidden by the syntax of individual languages. Im folgenden Beispiel enthält ein generischer Typ Outer<T> zwei geschachtelte Klassen: Inner1A und Inner1B<U>.In the following example, a generic type Outer<T> contains two nested classes, Inner1A and Inner1B<U>. Die Aufrufe der ToString-Methode, die jede Klasse von Object.ToString erbt, zeigen, dass jede geschachtelte Klasse die Typparameter der enthaltenden Klasse umfasst.The calls to the ToString method, which each class inherits from Object.ToString, show that each nested class includes the type parameters of its containing class.

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]

Der Name eines generischen Typs wird in der Form name`n codiert, wobei name der Typname, ` ein Zeichenliteral und n die Anzahl von Parametern ist, die für den Typ deklariert sind, oder, bei geschachtelten generischen Typen, die Anzahl neu eingeführter Typparameter.Generic type names are encoded in the form name`n, where name is the type name, ` is a character literal, and n is the number of parameters declared on the type, or, for nested generic types, the number of newly introduced type parameters. Diese Codierung von Namen des generischen Typs ist hauptsächlich für Entwickler relevant, die Reflexion verwenden, um auf CLS-kompatible generische Typen in einer Bibliothek zuzugreifen.This encoding of generic type names is primarily of interest to developers who use reflection to access CLS-complaint generic types in a library.

Wenn Einschränkungen auf einen generischen Typ angewendet werden, müssen alle als Einschränkungen verwendeten Typen auch CLS-kompatibel sein.If constraints are applied to a generic type, any types used as constraints must also be CLS-compliant. Im folgenden Beispiel wird eine Klasse namens BaseClass definiert, die nicht CLS-kompatibel ist sowie eine generische Klasse namens BaseCollection deren Typparameter von BaseClass abgeleitet werden muss.The following example defines a class named BaseClass that is not CLS-compliant and a generic class named BaseCollection whose type parameter must derive from BaseClass. Aber, da BaseClass nicht CLS-kompatibel ist, gibt der Compiler eine Warnung aus.But because BaseClass is not CLS-compliant, the compiler emits a warning.

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)
'                                        ~~~~~~~~~

Wenn ein generischer Typ von einem generischen Basistyp abgeleitet ist, muss er alle Einschränkungen erneut deklarieren, damit sichergestellt ist, dass auch die Einschränkungen des Basistyps erfüllt werden.If a generic type is derived from a generic base type, it must redeclare any constraints so that it can guarantee that constraints on the base type are also satisfied. Im folgenden Beispiel wird Number<T> definiert, das einen numerischen Typ darstellen kann.The following example defines a Number<T> that can represent any numeric type. Es definiert auch eine FloatingPoint<T>-Klasse, die einen Gleitkommawert darstellt.It also defines a FloatingPoint<T> class that represents a floating point value. Allerdings kann der Quellcode nicht kompiliert werden, da die Einschränkung auf Number<T> (dieses T muss ein Werttyp sein) nicht auf FloatingPoint<T> angewendet werden.However, the source code fails to compile, because it does not apply the constraint on Number<T> (that T must be a value type) to 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 comple 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 comple 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)
'                                                          ~

Das Beispiel wird erfolgreich kompiliert, wenn die Einschränkung der FloatingPoint<T>-Klasse hinzugefügt wird.The example compiles successfully if the constraint is added to the FloatingPoint<T> class.

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           

Die Common Language Specification erzwingt ein konservatives Pro-Instanziierungsmodell für geschachtelte Typen und geschützte Member.The Common Language Specification imposes a conservative per-instantiation model for nested types and protected members. Offene generische Typen können Felder oder Member mit Signaturen nicht verfügbar machen, die eine bestimmte Instanziierung eines geschachtelten, geschützten generischen Typs enthalten.Open generic types cannot expose fields or members with signatures that contain a specific instantiation of a nested, protected generic type. Nicht generische Typen, die eine bestimmte Instanziierung einer generischen Basisklasse oder Schnittstelle erweitern, können Felder oder Member mit Signaturen nicht verfügbar machen, die eine andere Instanziierung eines geschachtelten, geschützten generischen Typs enthalten.Non-generic types that extend a specific instantiation of a generic base class or interface cannot expose fields or members with signatures that contain a different instantiation of a nested, protected generic type.

Im folgenden Beispiel wird ein generischer Typ, C1<T> (oder C1(Of T) in Visual Basic) und eine geschützte Klasse, C1<T>.N (oder C1(Of T).N in Visual Basic) definiert.The following example defines a generic type, C1<T> (or C1(Of T) in Visual Basic), and a protected class, C1<T>.N (or C1(Of T).N in Visual Basic). C1<T> verfügt über zwei Methoden, M1 und M2.C1<T> has two methods, M1 and M2. Allerdings ist M1 nicht CLS-kompatibel, da versucht wird, ein C1<int>.N-Objekt (oder C1(Of Integer).N)-Objekt von C1<T> (oder C1(Of T)) zurückzugeben.However, M1 is not CLS-compliant because it tries to return a C1<int>.N (or C1(Of Integer).N) object from C1<T> (or C1(Of T)). Eine zweite Klasse, C2, ist von C1<long> abgeleitet (oder von C1(Of Long)).A second class, C2, is derived from C1<long> (or C1(Of Long)). Sie verfügt über zwei Methoden, M3 und M4.It has two methods, M3 and M4. M3 ist nicht CLS-kompatibel, da versucht wird, ein C1<int>.N-Objekt (oder C1(Of Integer).N) einer Unterklasse von C1<long> zurückzugeben.M3 is not CLS-compliant because it tries to return a C1<int>.N (or C1(Of Integer).N) object from a subclass of C1<long>. Beachten Sie, dass Sprachcompiler sogar noch restriktiver sein können.Note that language compilers can be even more restrictive. In diesem Beispiel zeigt Visual Basic einen Fehler an, wenn versucht wird, M4 zu kompilieren.In this example, Visual Basic displays an error when it tries to compile M4.

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)  
'                             ~~~~~~~~~~~~~

KonstruktorenConstructors

Bei Konstruktoren in den CLS-kompatiblen Klassen und Strukturen müssen die folgenden Regeln beachtet werden:Constructors in CLS-compliant classes and structures must follow these rules:

  • Der Konstruktor einer abgeleiteten Klasse muss den Instanzkonstruktor der Basisklasse aufrufen, bevor er auf geerbte Instanzdaten zugreift.A constructor of a derived class must call the instance constructor of its base class before it accesses inherited instance data. Diese Anforderung basiert auf der Tatsache, dass Konstruktoren nicht nach ihren abgeleiteten Klassen geerbt werden.This requirement is due to the fact that base class constructors are not inherited by their derived classes. Diese Regel gilt nicht für Strukturen, die keine direkte Vererbung unterstützen.This rule does not apply to structures, which do not support direct inheritance.

    In der Regel erzwingen Compiler diese Regel unabhängig von der CLS-Kompatibilität, wie im folgenden Beispiel gezeigt.Typically, compilers enforce this rule independently of CLS compliance, as the following example shows. Es wird eine Doctor-Klasse erstellt, die von einer Person-Klasse abgeleitet ist. Doch die Doctor-Klasse kann den Person-Klassenkonstruktor nicht zum Initialisieren geerbter Instanzfelder aufrufen.It creates a Doctor class that is derived from a Person class, but the Doctor class fails to call the Person class constructor to initialize inherited instance fields.

    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()
    '                  ~~~
    
  • Ein Objektkonstruktor kann nur aufgerufen werden, um ein Objekt zu erstellen.An object constructor cannot be called except to create an object. Außerdem kann ein Objekt nicht zweimal initialisiert werden.In addition, an object cannot be initialized twice. Das bedeutet zum Beispiel, dass Object.MemberwiseClone und solche Deserialisierungsmethoden wie BinaryFormatter.Deserialize keine Konstruktoren aufrufen dürfen.For example, this means that Object.MemberwiseClone and deserialization methods such as BinaryFormatter.Deserialize must not call constructors.

EigenschaftenProperties

Eigenschaften in den CLS-kompatiblen Typen müssen die folgenden Regeln beachten:Properties in CLS-compliant types must follow these rules:

  • Eine Eigenschaft muss über einen Setter, einen Getter oder beides verfügen.A property must have a setter, a getter, or both. In einer Assembly werden diese als spezielle Methoden implementiert, das bedeutet, dass sie als separate Methoden (der Getter hat den Namen get_Eigenschaftsname und der Setter den Namen set_Eigenschaftsname) erscheinen, die als SpecialName gekennzeichnet in den Metadaten der Assembly angezeigt werden.In an assembly, these are implemented as special methods, which means that they will appear as separate methods (the getter is named get_propertyname and the setter is set_propertyname) marked as SpecialName in the assembly's metadata. Die Compiler von C# und Visual Basic erzwingen diese Regel automatisch, ohne das CLSCompliantAttribute-Attribut anzuwenden.The C# and Visual Basic compilers enforce this rule automatically without the need to apply the CLSCompliantAttribute attribute.

  • Ein Typ der Eigenschaft entspricht dem Rückgabetyp der Getter-Methode der Eigenschaft und dem letzen Argument der Setter-Methode.A property's type is the return type of the property getter and the last argument of the setter. Diese Typen müssen CLS-kompatibel sein, und Argumente können der Eigenschaft nicht mithilfe eines Verweises zugewiesen werden (das heißt, es können keine verwalteten Zeiger sein).These types must be CLS compliant, and arguments cannot be assigned to the property by reference (that is, they cannot be managed pointers).

  • Wenn eine Eigenschaft einen Getter und einen Setter aufweist, müssen beide "virtual", "static" oder "instance" sein.If a property has both a getter and a setter, they must both be virtual, both static, or both instance. Die Compiler von C#- und Visual Basic erzwingen diese Regel automatisch mithilfe der Eigenschaftendefinitionssyntax.The C# and Visual Basic compilers automatically enforce this rule through their property definition syntax.

EreignisseEvents

Ein Ereignis wird vom Namen und dem Typ definiert.An event is defined by its name and its type. Der Ereignistyp ist ein Delegat, der zum Angeben des Ereignisses verwendet wird.The event type is a delegate that is used to indicate the event. Zum Beispiel hat das AppDomain.AssemblyResolve-Ereignis den Typ ResolveEventHandler.For example, the AppDomain.AssemblyResolve event is of type ResolveEventHandler. Neben dem Ereignis selbst, stellen drei Methoden mit Namen basierend auf dem Ereignisnamen die Implementierung des Ereignisses bereit und werden in den Metadaten der Assembly als SpecialName gekennzeichnet:In addition to the event itself, three methods with names based on the event name provide the event's implementation and are marked as SpecialName in the assembly's metadata:

  • Eine Methode zum Hinzufügen eines Ereignishandlers namens add_Ereignisname.A method for adding an event handler, named add_EventName. Die Ereignisabonnementmethode für das AppDomain.AssemblyResolve-Ereignis hat zum Beispiel den Namen add_AssemblyResolve.For example, the event subscription method for the AppDomain.AssemblyResolve event is named add_AssemblyResolve.

  • Eine Methode zum Entfernen eines Ereignishandlers namens remove_Ereignisname.A method for removing an event handler, named remove_EventName. Die Entfernenmethode für das AppDomain.AssemblyResolve-Ereignis hat zum Beispiel den Namen remove_AssemblyResolve.For example, the removal method for the AppDomain.AssemblyResolve event is named remove_AssemblyResolve.

  • Eine Methode für den Hinweis, dass das Ereignis namens raise_Ereignisname aufgetreten ist.A method for indicating that the event has occurred, named raise_EventName.

Hinweis

Die meisten Regeln der Common Language Specification zu Ereignissen werden von den Sprachcompilern implementiert und sind für Komponentenentwickler transparent.Most of the Common Language Specification's rules regarding events are implemented by language compilers and are transparent to component developers.

Die Methoden für das Hinzufügen, Entfernen und Auslösen des Ereignisses verfügen über den gleichen Zugriff.The methods for adding, removing, and raising the event must have the same accessibility. Sie müssen zudem "static", "instance" oder "virtual" sein.They must also all be static, instance, or virtual. Die Methoden zum Hinzufügen und Entfernen eines Ereignisses verfügen über einen Parameter, dessen Typ der Ereignisdelegattyp ist.The methods for adding and removing an event have one parameter whose type is the event delegate type. Die Methoden zum Hinzufügen und Entfernen müssen beide vorhanden sein oder beide fehlen.The add and remove methods must both be present or both be absent.

Im folgenden Beispiel wird eine CLS-kompatible Klasse namens Temperature definiert, die ein TemperatureChanged-Ereignis auslöst, wenn die Temperaturänderung zwischen zwei Messungen einem Schwellenwert entspricht oder diesen überschreitet.The following example defines a CLS-compliant class named Temperature that raises a TemperatureChanged event if the change in temperature between two readings equals or exceeds a threshold value. Die Temperature-Klasse definiert eine raise_TemperatureChanged-Methode explizit, sodass sie selektiv Ereignishandler ausführen kann.The Temperature class explicitly defines a raise_TemperatureChanged method so that it can selectively execute event handlers.

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

OverloadsOverloads

Die Common Language Specification erzwingt die folgenden Anforderungen für überladene Member:The Common Language Specification imposes the following requirements on overloaded members:

  • Member können auf Grundlage der Anzahl und des Typs eines Parameters überladen werden.Members can be overloaded based on the number of parameters and the type of any parameter. Aufrufkonvention, Rückgabetyp, die benutzerdefinierten Modifizierer, die auf die Methode oder deren Parameter angewendet werden und, ob Parameter nach Wert oder nach Verweis übergeben werden, werden bei der Unterscheidung zwischen Überladungen nicht beachtet.Calling convention, return type, custom modifiers applied to the method or its parameter, and whether parameters are passed by value or by reference are not considered when differentiating between overloads. Ein Beispiel finden Sie im Abschnitt Namenskonventionen im Code für die Anforderung, dass Namen innerhalb eines Bereichs eindeutig sein müssen.For an example, see the code for the requirement that names must be unique within a scope in the Naming conventions section.

  • Nur Eigenschaften und Methoden können überladen werden.Only properties and methods can be overloaded. Felder und Ereignisse können nicht überladen werden.Fields and events cannot be overloaded.

  • Generische Methoden können auf Grundlage der Anzahl ihrer generischen Parameter überladen werden.Generic methods can be overloaded based on the number of their generic parameters.

Hinweis

Der op_Explicit-Operator und der op_Implicit-Operator sind Ausnahmen von der Regel, dass Rückgabewerte nicht als Teil einer Methodensignatur für Überladungsauflösung gelten.The op_Explicit and op_Implicit operators are exceptions to the rule that return value is not considered part of a method signature for overload resolution. Diese beiden Operatoren können auf Grundlage ihrer Parameter und ihrer Rückgabewerte überladen werden.These two operators can be overloaded based on both their parameters and their return value.

AusnahmenExceptions

Ausnahmeobjekte müssen von System.Exception oder von einem anderen Typ abgeleitet werden, der von System.Exception abgeleitet wird.Exception objects must derive from System.Exception or from another type derived from System.Exception. Im folgenden Beispiel wird der Compilerfehler veranschaulicht, der entsteht, wenn eine benutzerdefinierte Klasse namens ErrorClass für die Ausnahmebehandlung verwendet wird.The following example illustrates the compiler error that results when a custom class named ErrorClass is used for exception handling.

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
'             ~~~~~~~~~~~~~~

Um diesen Fehler zu beheben, muss die ErrorClass-Klasse von System.Exception erben.To correct this error, the ErrorClass class must inherit from System.Exception. Außerdem muss die Message- Eigenschaft überschrieben werden.In addition, the Message property must be overridden. Im folgenden Beispiel werden diese Fehler korrigiert, um eine CLS-kompatible ErrorClass-Klasse zu definieren.The following example corrects these errors to define an ErrorClass class that is CLS-compliant.

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

AttributeAttributes

In .NET-Frameworkassemblys stellen benutzerdefinierte Attribute einen erweiterbaren Mechanismus zum Speichern benutzerdefinierter Attribute und das Abrufen von Metadaten über Programmierobjekte, wie Assemblys, Typen, Member und Methodenparameter, bereit.In.NET Framework assemblies, custom attributes provide an extensible mechanism for storing custom attributes and retrieving metadata about programming objects, such as assemblies, types, members, and method parameters. Benutzerdefinierte Attribute müssen von System.Attribute oder einem Typ abgeleitet werden, der von System.Attribute abgeleitet wird.Custom attributes must derive from System.Attribute or from a type derived from System.Attribute.

Das folgende Beispiel verstößt gegen diese Regel.The following example violates this rule. Es wird eine NumericAttribute-Klasse definiert, die nicht von System.Attribute abgeleitet ist.It defines a NumericAttribute class that does not derive from System.Attribute. Beachten Sie, dass der Compilerfehler nur entsteht, wenn das nicht CLS-kompatible Attribut angewendet wird, nicht aber, wenn die Klasse definiert ist.Note that a compiler error results only when the non-CLS-compliant attribute is applied, not when the class is defined.

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
'     ~~~~~~~~~~~~~

Der Konstruktor oder die Eigenschaften eines CLS-kompatiblen Attributs können nur die folgenden Typen verfügbar machen:The constructor or the properties of a CLS-compliant attribute can expose only the following types:

Im folgenden Beispiel wird eine von DescriptionAttribute abgeleitete Attribute-Klasse definiert.The following example defines a DescriptionAttribute class that derives from Attribute. Der Klassenkonstruktor verfügt über einen Parameter des Typs Descriptor, sodass die Klasse nicht CLS-kompatibel ist.The class constructor has a parameter of type Descriptor, so the class is not CLS-compliant. Beachten Sie, dass der C#-Compiler eine Warnung ausgibt, aber erfolgreich kompiliert, während der Visual Basic-Compiler weder eine Warnung noch einen Fehler ausgibt.Note that the C# compiler emits a warning but compiles successfully, whereas the Visual Basic compiler emits neither a warning nor an error.

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

Das CLSCompliantAttribute-AttributThe CLSCompliantAttribute attribute

Das CLSCompliantAttribute-Attribut wird verwendet, um anzugeben, ob ein Programmelement mit der Common Language Specification kompatibel ist.The CLSCompliantAttribute attribute is used to indicate whether a program element complies with the Common Language Specification. Der CLSCompliantAttribute.CLSCompliantAttribute(Boolean)-Konstruktor enthält einen einzelnen erforderlichen Parameter, isCompliant, der angibt, ob das Programmelement CLS-kompatibel ist.The CLSCompliantAttribute.CLSCompliantAttribute(Boolean) constructor includes a single required parameter, isCompliant, that indicates whether the program element is CLS-compliant.

Zur Kompilierzeit erkennt der Compiler nicht kompatible Elemente, von denen angenommen wird, dass sie CLS-kompatibel sind, und gibt eine Warnung aus.At compile time, the compiler detects non-compliant elements that are presumed to be CLS-compliant and emits a warning. Der Compiler gibt keine Warnungen für die Typen oder Member aus, die explizit als nicht kompatibel deklariert werden.The compiler does not emit warnings for types or members that are explicitly declared to be non-compliant.

Komponentenentwickler können das CLSCompliantAttribute-Attribut auf zwei Arten verwenden:Component developers can use the CLSCompliantAttribute attribute in two ways:

  • Um die Teile der öffentlichen Schnittstelle zu definieren, die von einer CLS-kompatiblen Komponente und den nicht CLS-kompatiblen Teilen verfügbar gemacht werden.To define the parts of the public interface exposed by a component that are CLS-compliant and the parts that are not CLS-compliant. Wenn das Attribut verwendet wird, um bestimmte Programmelemente als CLS-kompatibel zu markieren, stellt seine Verwendung sicher, dass auf diese Elemente aus allen Sprachen und Tools für das .NET Framework zugegriffen werden kann.When the attribute is used to mark particular program elements as CLS-compliant, its use guarantees that those elements are accessible from all languages and tools that target the .NET Framework.

  • Um sicherzustellen, dass die öffentliche Schnittstelle der Komponentenbibliothek nur Programmelemente verfügbar macht, die CLS-kompatibel sind.To ensure that the component library's public interface exposes only program elements that are CLS-compliant. Wenn Elemente nicht CLS-kompatibel sind, geben Compiler im Allgemeinen eine Warnung aus.If elements are not CLS-compliant, compilers will generally issue a warning.

Warnung

In einigen Fällen erzwingen CLS-kompatible Sprachcompiler Regeln unabhängig davon, ob das CLSCompliantAttribute-Attribut verwendet wird.In some cases, language compilers enforce CLS-compliant rules regardless of whether the CLSCompliantAttribute attribute is used. Das Definieren eines statischen Members in einer Schnittstelle verstößt zum Beispiel gegen eine CLS-Regel.For example, defining a static member in an interface violates a CLS rule. In dieser Hinsicht, wenn Sie definieren eine static (in c#) oder Shared (in Visual Basic) Member in einer Schnittstelle, sowohl die C#- und Visual Basic-Compiler eine Fehlermeldung angezeigt, und Fehler beim Kompilieren der app.In this regard, if you define a static (in C#) or Shared (in Visual Basic) member in an interface, both the C# and Visual Basic compilers display an error message and fail to compile the app.

Das CLSCompliantAttribute-Attribut wird mit einem AttributeUsageAttribute-Attribut markiert, das über einen Wert von AttributeTargets.All verfügt.The CLSCompliantAttribute attribute is marked with an AttributeUsageAttribute attribute that has a value of AttributeTargets.All. Dieser Wert ermöglicht das Anwenden des CLSCompliantAttribute-Attributs auf jedem Programmelement, einschließlich Assemblys, Modulen, Typen (Klassen, Strukturen, Enumerationen, Schnittstellen und Delegaten), Typmembern (Konstruktoren, Methoden, Eigenschaften, Feldern und Ereignissen), Parametern, generischen Parametern und Rückgabewerten.This value allows you to apply the CLSCompliantAttribute attribute to any program element, including assemblies, modules, types (classes, structures, enumerations, interfaces, and delegates), type members (constructors, methods, properties, fields, and events), parameters, generic parameters, and return values. In der Praxis sollten Sie das Attribut allerdings nur auf Assemblys, Typen und Typmember anwenden.However, in practice, you should apply the attribute only to assemblies, types, and type members. Andernfalls ignorieren Compiler das Attribut und generieren weiterhin Compilerwarnungen, wenn sie einen nicht kompatiblen Parameter, einen generischen Parameter oder einen Rückgabewert in der öffentlichen Schnittstelle der Bibliothek vorfinden.Otherwise, compilers ignore the attribute and continue to generate compiler warnings whenever they encounter a non-compliant parameter, generic parameter, or return value in your library's public interface.

Der Wert des CLSCompliantAttribute-Attributs wird von enthaltenen Programmelementen geerbt.The value of the CLSCompliantAttribute attribute is inherited by contained program elements. Wenn beispielsweise eine Assembly als CLS-kompatibel markiert ist, sind die Typen auch CLS-kompatibel.For example, if an assembly is marked as CLS-compliant, its types are also CLS-compliant. Wenn ein Typ als CLS-kompatibel gekennzeichnet ist, sind seine geschachtelten Typen und Member auch CLS-kompatibel.If a type is marked as CLS-compliant, its nested types and members are also CLS-compliant.

Sie können die geerbte Kompatibilität explizit überschreiben, indem Sie das CLSCompliantAttribute- Attribut auf ein enthaltenes Programmelement anwenden.You can explicitly override the inherited compliance by applying the CLSCompliantAttribute attribute to a contained program element. Beispielsweise können Sie das CLSCompliantAttribute-Attribut mit einem Wert von isCompliant``false verwenden, um einen inkompatiblen Typ in einer kompatiblen Assembly zu definieren, und Sie können das Attribut mit einem Wert von isCompliant``true verwenden, um einen kompatiblen Typ in einer inkompatiblen Assembly zu definieren.For example, you can use the CLSCompliantAttribute attribute with an isCompliant value of false to define a non-compliant type in a compliant assembly, and you can use the attribute with an isCompliant value of true to define a compliant type in a non-compliant assembly. Sie können auch nicht kompatible Member in einem kompatiblen Typ definieren.You can also define non-compliant members in a compliant type. Allerdings kann ein nicht kompatibler Typ keine kompatiblen Member aufweisen, sodass Sie das Attribut nicht mit einem Wert von isCompliant``true verwenden können, um die Vererbung eines nicht kompatiblen Typs zu überschreiben.However, a non-compliant type cannot have compliant members, so you cannot use the attribute with an isCompliant value of true to override inheritance from a non-compliant type.

Wenn Sie Komponenten entwickeln, sollten Sie stets das CLSCompliantAttribute- Attribut verwenden, um anzugeben, ob die Assembly, die Typen und die Member CLS-kompatibel sind.When you are developing components, you should always use the CLSCompliantAttribute attribute to indicate whether your assembly, its types, and its members are CLS-compliant.

So erstellen Sie CLS-kompatible Komponenten:To create CLS-compliant components:

  1. Verwenden Sie CLSCompliantAttribute, um die Assembly als CLS-kompatibel zu markieren.Use the CLSCompliantAttribute to mark you assembly as CLS-compliant.

  2. Markieren Sie jeden öffentlich verfügbar gemachten, nicht CLS-kompatiblen Typ in der Assembly als nicht kompatibel.Mark any publicly exposed types in the assembly that are not CLS-compliant as non-compliant.

  3. Markieren Sie alle öffentlich verfügbar gemachten Member in CLS-kompatiblen Typen als nicht kompatibel.Mark any publicly exposed members in CLS-compliant types as non-compliant.

  4. Stellen Sie eine CLS-kompatible Alternative für nicht CLS-kompatible Member bereit.Provide a CLS-compliant alternative for non-CLS-compliant members.

Wenn alle inkompatiblen Typen und Member erfolgreich markiert wurden, sollte der Compiler keine Kompatibilitätswarnungen ausgeben.If you've successfully marked all your non-compliant types and members, your compiler should not emit any non-compliance warnings. Allerdings sollten Sie angeben, welche Member nicht CLS-kompatibel sind und ihre CLS-kompatiblen Alternativen in der Produktdokumentation aufführen.However, you should indicate which members are not CLS-compliant and list their CLS-compliant alternatives in your product documentation.

Im folgenden Beispiel wird das CLSCompliantAttribute-Attribut verwendet, um eine CLS-kompatible Assembly und einen Typ, CharacterUtilities, zu definieren, der über zwei nicht CLS-kompatible Member verfügt.The following example uses the CLSCompliantAttribute attribute to define a CLS-compliant assembly and a type, CharacterUtilities, that has two non-CLS-compliant members. Da beide Member mit dem CLSCompliant(false)-Attribut markiert sind, generiert der Compiler keine Warnungen.Because both members are tagged with the CLSCompliant(false) attribute, the compiler produces no warnings. Die Klasse stellt auch eine CLS-kompatible Alternative für beide Methoden bereit.The class also provides a CLS-compliant alternative for both methods. Normalerweise würden der ToUTF16- Methode lediglich zwei Überladungen hinzugefügt werden, um CLS-kompatible Alternativen bereitzustellen.Ordinarily, we would just add two overloads to the ToUTF16 method to provide CLS-compliant alternatives. Da Methoden aber nicht aufgrund des Rückgabewerts überladen werden können, sind die Namen der CLS-kompatiblen Methoden von den Namen der nicht kompatiblen Methoden unterschiedlich.However, because methods cannot be overloaded based on return value, the names of the CLS-compliant methods are different from the names of the non-compliant methods.

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

Wenn Sie eine App anstelle einer Bibliothek entwickeln, (das heißt, wenn Sie keine Typen oder Member verfügbar machen, die von anderen App-Entwicklern genutzt werden können), ist die CLS-Kompatibilität der Programmelemente, die von der App genutzt werden, nur relevant, wenn sie von Ihrer Sprache nicht unterstützt werden.If you are developing an app rather than a library (that is, if you aren't exposing types or members that can be consumed by other app developers), the CLS compliance of the program elements that your app consumes are of interest only if your language does not support them. In diesem Fall generiert der Sprachcompiler einen Fehler, wenn Sie versuchen, ein nicht CLS-kompatibles Element zu verwenden.In that case, your language compiler will generate an error when you try to use a non-CLS-compliant element.

Sprachübergreifende InteroperabilitätCross-Language Interoperability

Der Begriff „Sprachunabhängigkeit“ kann mehrere Bedeutungen haben.Language independence has a number of possible meanings. Eine Bedeutung, die im Artikel Sprachenunabhängigkeit und sprachunabhängige Komponenten erläutert wird, bezeichnet die nahtlose Nutzung von Typen, die in einer Sprache geschrieben wurden, durch eine App, die in einer anderen Sprache geschrieben wurde.One meaning, which is discussed in the article Language Independence and Language-Independent Components, involves seamlessly consuming types written in one language from an app written in another language. Eine zweite Bedeutung, die in diesem Artikels hervorgehoben wird, umfasst die Kombination von Code aus mehreren Sprachen in einer einzelnen .NET Framework-Assembly.A second meaning, which is the focus of this article, involves combining code written in multiple languages into a single .NET Framework assembly.

Das folgende Beispiel veranschaulicht die sprachübergreifende Interoperabilität. Es wird die Klassenbibliothek Utilities.dll erstellt, die zwei Klassen einschließt: NumericLib und StringLib.The following example illustrates cross-language interoperability by creating a class library named Utilities.dll that includes two classes, NumericLib and StringLib. Die NumericLib-Klasse wurde in C# und die StringLib-Klasse in Visual Basic geschrieben.The NumericLib class is written in C#, and the StringLib class is written in Visual Basic. Im Folgenden sehen Sie den Quellcode für "StringUtil.vb", der in der ToTitleCase-Klasse einen einzelnen Member enthält, StringLib.Here's the source code for StringUtil.vb, which includes a single member, ToTitleCase, in its StringLib class.

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

Im Folgenden sehen Sie den Quellcode für "NumberUtil.cs", der eine NumericLib-Klasse mit zwei Membern definiert: IsEven und NearZero.Here's the source code for NumberUtil.cs, which defines a NumericLib class that has two members, IsEven and 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; 
   }
}

Um die beiden Klassen in einer einzelnen Assembly zu verpacken, müssen Sie sie in Module kompilieren.To package the two classes in a single assembly, you must compile them into modules. Verwenden Sie zum Kompilieren der Visual Basic-Quellcodedatei in einem Modul folgenden Befehl:To compile the Visual Basic source code file into a module, use this command:

vbc /t:module StringUtil.vb   

Weitere Informationen zur Befehlszeilensyntax des Visual Basic-Compilers finden Sie unter Erstellen von der Befehlszeile aus.For more information about the command-line syntax of the Visual Basic compiler, see Building from the Command Line.

Verwenden Sie zum Kompilieren der C#-Quellcodedatei in einem Modul folgenden Befehl:To compile the C# source code file into a module, use this command:

csc /t:module NumberUtil.cs  

Weitere Informationen zur Befehlszeilensyntax des C#-Compilers finden Sie unter Erstellen über die Befehlszeile mit csc.exe.For more information about the command-line syntax of the C# compiler, see Command-line Building With csc.exe.

Verwenden Sie dann das Linktool (Link.exe), um die beiden Module in eine Assembly zu kompilieren:You then use the Link tool (Link.exe) to compile the two modules into an assembly:

link numberutil.netmodule stringutil.netmodule /out:UtilityLib.dll /dll   

Das folgende Beispiel ruft dann die NumericLib.NearZero-Methode und die StringLib.ToTitleCase-Methode auf.The following example then calls the NumericLib.NearZero and StringLib.ToTitleCase methods. Beachten Sie, dass sowohl der Visual Basic-Code als auch der C#-Code auf die Methoden in beiden Klassen zugreifen können.Note that both the Visual Basic code and the C# code are able to access the methods in both classes.

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

Verwenden Sie zum Kompilieren des Visual Basic-Codes folgenden Befehl:To compile the Visual Basic code, use this command:

vbc example.vb /r:UtilityLib.dll  

Zum Kompilieren mit C# ändern Sie den Namen des Compilers von vbc in csc und die Dateierweiterung von „.vb“ in „.cs“:To compile with C#, change the name of the compiler from vbc to csc, and change the file extension from .vb to .cs:

csc example.cs /r:UtilityLib.dll  

Siehe auchSee Also

CLSCompliantAttribute