Indipendenza del linguaggio e componenti indipendenti dal linguaggioLanguage Independence and Language-Independent Components

.NET Framework è indipendente dal linguaggio.The .NET Framework is language independent. In qualità di sviluppatore, è pertanto possibile usare uno dei numerosi linguaggi destinati a .NET Framework, ad esempio C#, C++/CLI, Eiffel, F#, IronPython, IronRuby, PowerBuilder, Visual Basic, Visual COBOL e 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. È possibile accedere a tipi e membri di librerie di classi sviluppate per .NET Framework senza dover conoscere il linguaggio in cui sono stati originariamente scritti e senza dover seguire nessuna delle convenzioni del linguaggio originale.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. Se si è uno sviluppatore di componenti, l'accesso al componente può essere eseguito da qualsiasi applicazione .NET Framework, indipendentemente dal linguaggio.If you are a component developer, your component can be accessed by any .NET Framework app regardless of its language.

Nota

La prima parte di questo articolo illustra la creazione di componenti indipendenti dal linguaggio, vale a dire componenti che possono essere usati da applicazioni scritte in qualsiasi linguaggio.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. È anche possibile creare un singolo componente o applicazione dal codice sorgente scritto in più linguaggi. Vedere Interoperabilità tra linguaggi diversi nella seconda parte di questo articolo.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.

È necessario che gli oggetti espongano ai chiamanti solo le funzionalità comuni a tutti i linguaggi, affinché sia garantita un'interazione completa con altri oggetti scritti in uno qualsiasi dei linguaggi.To fully interact with other objects written in any language, objects must expose to callers only those features that are common to all languages. Questo set comune di funzionalità è definito dalle specifiche CLS (Common Language Specification), un set di regole che si applicano agli assembly generati.This common set of features is defined by the Common Language Specification (CLS), which is a set of rules that apply to generated assemblies. La specifica CLS (Common Language Specification) è definita nella partizione I, clausole da 7 a 11 dello standard ECMA-335 di Common Language Infrastructure.The Common Language Specification is defined in Partition I, Clauses 7 through 11 of the ECMA-335 Standard: Common Language Infrastructure.

Se il componente è conforme alle specifiche CLS (Common Language Specification), ne è garantita la conformità a CLS ed è possibile accedervi dal codice negli assembly scritti in qualsiasi linguaggio di programmazione che supporti CLS.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. È possibile determinare se il componente è conforme alle specifiche CLS (Common Language Specification) in fase di compilazione applicando l'attributo CLSCompliantAttribute al codice sorgente.You can determine whether your component conforms to the Common Language Specification at compile time by applying the CLSCompliantAttribute attribute to your source code. Per altre informazioni, vedere Attributo CLSCompliantAttribute.For more information, see The CLSCompliantAttribute attribute.

Contenuto dell'articolo:In this article:

Regole di conformità a CLSCLS compliance rules

In questa sezione vengono illustrate le regole per creare un componente conforme a CLS.This section discusses the rules for creating a CLS-compliant component. Per un elenco completo delle regole, vedere la partizione I, clausola 11 dello standard ECMA-335 di Common Language Infrastructure.For a complete list of rules, see Partition I, Clause 11 of the ECMA-335 Standard: Common Language Infrastructure.

Nota

Nelle specifiche CLS (Common Language Specification) viene illustrata ciascuna regola per la conformità a CLS applicata ai consumer (sviluppatori che accedono a livello di codice a un componente conforme a CLS), ai framework (sviluppatori che usano un compilatore di linguaggio per creare librerie conformi a CLS) e alle estensioni (sviluppatori che creano uno strumento quale un compilatore di linguaggio o un parser di codice per la creazione di componenti conformi a CLS).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). Questo articolo è incentrato sulle regole che si applicano ai framework.This article focuses on the rules as they apply to frameworks. Si noti, tuttavia, che alcune delle regole applicate alle estensioni possono essere applicate anche agli assembly creati usando Reflection.Emit.Note, though, that some of the rules that apply to extenders may also apply to assemblies that are created using Reflection.Emit.

Per progettare un componente indipendente dal linguaggio, è necessario applicare le regole per la conformità a CLS solo all'interfaccia pubblica del componente.To design a component that is language independent, you only need to apply the rules for CLS compliance to your component's public interface. L'implementazione privata non deve essere conforme alla specifica.Your private implementation does not have to conform to the specification.

Importante

Le regole per la conformità a CLS si applicano solo all'interfaccia pubblica di un componente, non alla relativa implementazione privata.The rules for CLS compliance apply only to a component's public interface, not to its private implementation.

Ad esempio, Unsigned Integer diversi da Byte non sono conformi a CLS.For example, unsigned integers other than Byte are not CLS-compliant. Poiché tramite la classe Person nell'esempio seguente viene esposta una proprietà Age di tipo UInt16, nel codice riportato di seguito viene visualizzato un avviso del compilatore.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
'                                ~~~

È possibile rendere la classe Person conforme a CLS modificando il tipo di proprietà Age da UInt16 a Int16, vale a dire un Signed Integer a 16 bit conforme a CLS.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. Non è necessario modificare il tipo del campo personAge privato.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

L'interfaccia pubblica di una libreria è costituita dagli elementi seguenti:A library's public interface consists of the following:

  • Definizioni di classi pubbliche.Definitions of public classes.

  • Definizioni dei membri pubblici di classi pubbliche e definizioni di membri accessibili alle classi derivate, cioè membri protetti.Definitions of the public members of public classes, and definitions of members accessible to derived classes (that is, protected members).

  • Parametri e tipi restituiti di metodi pubblici di classi pubbliche e parametri e tipi restituiti di metodi accessibili alle classi derivate.Parameters and return types of public methods of public classes, and parameters and return types of methods accessible to derived classes.

Le regole per la conformità a CLS sono elencate nella tabella riportata di seguito.The rules for CLS compliance are listed in the following table. Il testo delle regole è preso letteralmente dallo standard ECMA-335 di Common Language Infrastructure, protetto da copyright 2012 di 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. Nelle sezioni seguenti sono disponibili informazioni più dettagliate su queste regole.More detailed information about these rules is found in the following sections.

CategoryCategory VedereSee RegolaRule Numero regolaRule number
AccessibilitàAccessibility Accessibilità del membroMember accessibility L'accessibilità non sarà modificata quando si esegue l'override di metodi ereditati, tranne nel caso in cui si esegue l'override di un metodo ereditato da un assembly diverso con accessibilità family-or-assembly.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 questo caso, l'override disporrà dell'accessibilità family.In this case, the override shall have accessibility family. 1010
AccessibilitàAccessibility Accessibilità del membroMember accessibility La visibilità e l'accessibilità di tipi e membri saranno tali che i tipi nella firma di qualsiasi membro saranno visibili e accessibili ogni volta che il membro stesso è visibile e accessibile.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. Ad esempio, in un metodo pubblico che è visibile all'esterno del relativo assembly non deve essere presente un argomento il cui tipo è visibile solo nell'assembly.For example, a public method that is visible outside its assembly shall not have an argument whose type is visible only within the assembly. La visibilità e l'accessibilità di tipi che compongono un tipo generico con istanze usato nella firma di qualsiasi membro saranno visibili e accessibili ogni volta che il membro stesso è visibile e accessibile.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. Ad esempio, in un tipo generico con istanze presente nella firma di un membro visibile all'esterno del relativo assembly non deve essere disponibile un argomento generico il cui tipo è visibile solo nell'assembly.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
MatriciArrays MatriciArrays Le matrici devono disporre di elementi con un tipo conforme a CLS e i limiti inferiori di tutte le dimensioni della matrice devono essere pari a zero.Arrays shall have elements with a CLS-compliant type, and all dimensions of the array shall have lower bounds of zero. Solo per il fatto che un elemento sia una matrice, il tipo di elemento della matrice sarà richiesto per eseguire una distinzione tra gli overload.Only the fact that an item is an array and the element type of the array shall be required to distinguish between overloads. Quando l'overload è basato su due o più i tipi di matrice, i tipi di elemento vengono denominati tipi.When overloading is based on two or more array types the element types shall be named types. 1616
AttributiAttributes AttributiAttributes Gli attributi devono essere di tipo System.Attribute o di un tipo che eredita da esso.Attributes shall be of type System.Attribute, or a type inheriting from it. 4141
AttributiAttributes AttributiAttributes La specifica CLS consente solo un subset delle codifiche di attributi personalizzati.The CLS only allows a subset of the encodings of custom attributes. Gli unici tipi che verranno visualizzati in queste codifiche sono (vedere la partizione IV): System.Type, System.String, System.Char, System.Boolean, System.Byte, System.Int16, System.Int32, System.Int64, System.Single, System.Double e qualsiasi tipo di enumerazione basato su un tipo Integer di base conforme a CLS.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
AttributiAttributes AttributiAttributes La specifica CLS non consente i modificatori necessari visibili pubblicamente (modreq, vedere la partizione II), ma consente i modificatori facoltativi (modopt, vedere la partizione II) che non riconosce.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
CostruttoriConstructors CostruttoriConstructors Prima di un eventuale accesso ai dati di istanza ereditati, tramite un costruttore di oggetti deve essere effettuata una chiamata a un costruttore di istanze della relativa classe di base.An object constructor shall call some instance constructor of its base class before any access occurs to inherited instance data. Ciò non si applica ai tipi di valore, che non devono disporre di costruttori.(This does not apply to value types, which need not have constructors.) 2121
CostruttoriConstructors CostruttoriConstructors Un costruttore di oggetti non deve essere chiamato se non come parte della creazione di un oggetto e un oggetto non deve essere inizializzato due volte.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
EnumerazioniEnumerations EnumerazioniEnumerations Il tipo sottostante di un'enumerazione deve essere un tipo Integer CLS incorporato, il nome del campo deve essere "value__" e il campo deve essere contrassegnato come RTSpecialName.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
EnumerazioniEnumerations EnumerazioniEnumerations Sono disponibili due tipi distinti di enumerazioni, indicati dalla presenza o dall'assenza dell'attributo personalizzato System.FlagsAttribute (vedere la libreria nella partizione IV).There are two distinct kinds of enums, indicated by the presence or absence of the System.FlagsAttribute (see Partition IV Library) custom attribute. Una rappresenta Integer denominati, l'altra flag di bit denominati che possono essere combinati per generare un valore senza nome.One represents named integer values; the other represents named bit flags that can be combined to generate an unnamed value. Il valore di un oggetto enum non è limitato ai valori specifici.The value of an enum is not limited to the specified values. 88
EnumerazioniEnumerations EnumerazioniEnumerations Il tipo dei campi statici con valori letterali di un'enumerazione deve essere uguale a quello dell'enumerazione stessa.Literal static fields of an enum shall have the type of the enum itself. 99
EventiEvents EventiEvents I metodi che implementano un evento devono essere contrassegnati come SpecialName nei metadati.The methods that implement an event shall be marked SpecialName in the metadata. 2929
EventiEvents EventiEvents L'accessibilità di un evento e le relative funzioni di accesso devono essere identiche.The accessibility of an event and of its accessors shall be identical. 3030
EventiEvents EventiEvents I metodi add e remove per un evento devono essere entrambi presenti o entrambi assenti.The add and remove methods for an event shall both either be present or absent. 3131
EventiEvents EventiEvents I metodi add e remove per un evento devono entrambi accettare un parametro tramite il cui tipo viene definito il tipo dell'evento e il tipo in questione deve essere derivato da System.Delegate.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
EventiEvents EventiEvents Gli eventi devono essere conformi a un pattern di nome specifico.Events shall adhere to a specific naming pattern. L'attributo SpecialName indicato nella regola CLS 29 deve essere ignorato nei confronti tra nomi appropriati e deve essere conforme alle regole dell'identificatore.The SpecialName attribute referred to in CLS rule 29 shall be ignored in appropriate name comparisons and shall adhere to identifier rules. 3333
EccezioniExceptions EccezioniExceptions Gli oggetti generati devono essere di tipo System.Exception o di un tipo che eredita da esso.Objects that are thrown shall be of type System.Exception or a type inheriting from it. Ciononostante, i metodi conformi a CLS non sono necessari per bloccare la propagazione di altri tipi di eccezioni.Nonetheless, CLS-compliant methods are not required to block the propagation of other types of exceptions. 4040
GeneraleGeneral Conformità a CLS: le regoleCLS compliance: the Rules Le regole CLS sono valide solo per le parti di un tipo che sono accessibili o visibili all'esterno dell'assembly di definizione.CLS rules apply only to those parts of a type that are accessible or visible outside of the defining assembly. 11
GeneraleGeneral Conformità a CLS: le regoleCLS compliance: the Rules I membri di tipi non conformi a CLS non saranno contrassegnati come conformi a CLS.Members of non-CLS compliant types shall not be marked CLS-compliant. 22
GenericsGenerics Tipi e membri genericiGeneric types and members I tipi annidati disporranno di un numero di parametri generici almeno pari a quelli del tipo di inclusione.Nested types shall have at least as many generic parameters as the enclosing type. I parametri generici di un tipo annidato corrispondono per posizione ai parametri generici del rispettivo tipo di inclusione.Generic parameters in a nested type correspond by position to the generic parameters in its enclosing type. 4242
GenericsGenerics Tipi e membri genericiGeneric types and members Con il nome di un tipo generico verrà codificato il numero di parametri di tipo dichiarati nel tipo non annidato o appena introdotti nel tipo se annidato, in base alle regole definite sopra.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
GenericsGenerics Tipi e membri genericiGeneric types and members Tramite un tipo generico deve essere dichiarato nuovamente un numero di vincoli sufficiente a garantire che qualsiasi vincolo delle interfacce o del tipo base venga soddisfatto dai vincoli del tipo generico.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
GenericsGenerics Tipi e membri genericiGeneric types and members I tipi usati come vincoli sui parametri generici dovranno essere essi stessi conformi a CLS.Types used as constraints on generic parameters shall themselves be CLS-compliant. 4545
GenericsGenerics Tipi e membri genericiGeneric types and members La visibilità e l'accessibilità di membri (compresi i tipi annidati) in un tipo generico con istanze devono essere considerate come limitate all'ambito della creazione di un'istanza specifica, anziché come dichiarazione del tipo generico nel suo complesso.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. Partendo da questo presupposto, valgono ancora le regole di visibilità e accessibilità della regola CLS 12.Assuming this, the visibility and accessibility rules of CLS rule 12 still apply. 4646
GenericsGenerics Tipi e membri genericiGeneric types and members Per ogni metodo generico astratto o virtuale, sarà necessaria un'implementazione concreta (non astratta) predefinita.For each abstract or virtual generic method, there shall be a default concrete (non-abstract) implementation. 4747
InterfacceInterfaces InterfacceInterfaces Per l'implementazione delle interfacce conformi a CLS, non sarà necessaria la definizione di metodi non conformi a CLS.CLS-compliant interfaces shall not require the definition of non-CLS compliant methods in order to implement them. 1818
InterfacceInterfaces InterfacceInterfaces Tramite le interfacce conformi a CLS non verranno definiti i metodi statici, né verranno definiti i campi.CLS-compliant interfaces shall not define static methods, nor shall they define fields. 1919
MembriMembers Membri dei tipi di in generaleType members in general I metodi e i campi static globali non sono conformi a CLS.Global static fields and methods are not CLS-compliant. 3636
MembriMembers -- Il valore di un valore statico letterale viene specificato attraverso l'uso dei metadati di inizializzazione del campo.The value of a literal static is specified through the use of field initialization metadata. Un valore letterale conforme a CLS deve disporre di un valore specificato nei metadati di inizializzazione del campo che sia esattamente dello stesso tipo del valore letterale, o del tipo sottostante, se questo valore letterale è un oggetto enum.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
MembriMembers Membri dei tipi di in generaleType members in general Il vincolo vararg non fa parte delle specifiche CLS e l'unica convenzione di chiamata supportata da CLS è la convenzione di chiamata gestita standard.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
Convenzioni di denominazioneNaming conventions Convenzioni di denominazioneNaming conventions Gli assembly seguiranno l'allegato 7 del rapporto tecnico 15 di Unicode Standard 3.0, con cui viene controllato il set di caratteri che possono essere usati all'inizio e all'interno degli identificatori, disponibili online nella pagina https://www.unicode.org/unicode/reports/tr15/tr15-18.html.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 online at https://www.unicode.org/unicode/reports/tr15/tr15-18.html. Gli identificatori dovranno essere nel formato canonico definito dal formato di normalizzazione Unicode C. Per scopi correlati a CLS, due identificatori sono identici se i rispettivi mapping delle minuscole (come specificato dai mapping di minuscole di tipo uno a uno, senza distinzione tra le impostazioni locali Unicode) sono uguali.Identifiers shall be in the canonical format defined by Unicode Normalization Form C. For CLS purposes, two identifiers are the same if their lowercase mappings (as specified by the Unicode locale-insensitive, one-to-one lowercase mappings) are the same. Vale a dire, affinché due identificatori vengano considerati differenti nella specifica CLS, devono presentare differenze che vanno oltre la semplice distinzione tra maiuscole e minuscole.That is, for two identifiers to be considered different under the CLS they shall differ in more than simply their case. Tuttavia, per eseguire l'override di una definizione non ereditata, CLI richiede l'uso della codifica precisa della dichiarazione originale.However, in order to override an inherited definition the CLI requires the precise encoding of the original declaration be used. 44
OverloadOverloading Convenzioni di denominazioneNaming conventions Tutti i nomi introdotti in un ambito conforme a CLS devono essere di tipo indipendente e distinto, fatta eccezione per i casi in cui i nomi sono identici e vengono risolti tramite l'overload.All names introduced in a CLS-compliant scope shall be distinct independent of kind, except where the names are identical and resolved via overloading. Laddove, ad esempio, CTS consente a un unico tipo di usare lo stesso nome per un metodo e per un campo, CLS non lo consente.That is, while the CTSallows a single type to use the same name for a method and a field, the CLS does not. 55
OverloadOverloading Convenzioni di denominazioneNaming conventions I campi e i tipi annidati devono essere distinti in base al solo confronto tra identificatori, anche se CTS permette la distinzione di firme distinte.Fields and nested types shall be distinct by identifier comparison alone, even though the CTS allows distinct signatures to be distinguished. I metodi, le proprietà e gli eventi che hanno lo stesso nome (in base al confronto degli identificatori) dovranno differire per più del tipo restituito, ad eccezione di quanto specificato nella regola CLS 39.Methods, properties, and events that have the same name (by identifier comparison) shall differ by more than just the return type,except as specified in CLS Rule 39. 66
OverloadOverloading OverloadOverloads È possibile eseguire l'overload solo di proprietà e metodi.Only properties and methods can be overloaded. 3737
OverloadOverloading OverloadOverloads Le proprietà e i metodi possono essere sottoposti a overload solo in base al numero e ai tipi dei relativi parametri, a eccezione degli operatori di conversione denominati op_Implicit e op_Explicit, i quali possono essere anche sottoposti a overload in base al relativo tipo restituito.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
OverloadOverloading -- Se due o più metodi conformi a CLS dichiarati in un tipo hanno lo stesso nome e, per un set specifico di creazioni di istanze del tipo, hanno lo stesso parametro e gli stesi tipi restituiti, tutti questi metodi saranno semanticamente equivalenti alle creazioni di istanze del tipo.If two or more CLS-compliant methods declared in a type have the same name and, for a specific set of type instantiations, they have the same parameter and return types, then all these methods shall be semantically equivalent at those type instantiations. 4848
TipiTypes Tipo e firme dei membri di tipoType and type member signatures System.Object è conforme a CLS.System.Object is CLS-compliant. Qualsiasi altra classe conforme a CLS deve ereditare da una classe conforme a CLS.Any other CLS-compliant class shall inherit from a CLS-compliant class. 2323
ProprietàProperties ProprietàProperties I metodi che implementano i metodi Get e Set di una proprietà devono essere contrassegnati come SpecialName nei metadati.The methods that implement the getter and setter methods of a property shall be marked SpecialName in the metadata. 2424
ProprietàProperties ProprietàProperties Le funzioni di accesso di una proprietà devono essere tutte statiche, tutte virtuali o tutte istanze.A property’s accessors shall all be static, all be virtual, or all be instance. 2626
ProprietàProperties ProprietàProperties Il tipo di una proprietà deve essere il tipo restituito del metodo Get e il tipo dell'ultimo argomento del metodo Set.The type of a property shall be the return type of the getter and the type of the last argument of the setter. I tipi dei parametri della proprietà devono essere i tipi dei parametri per il metodo Get e i tipi di tutti i parametri del metodo Set tranne l'ultimo.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. Tutti questi tipi devono essere conformi a CLS e non devono essere puntatori gestiti, cioè non devono essere passati per riferimento.All of these types shall be CLS-compliant, and shall not be managed pointers (i.e., shall not be passed by reference). 2727
ProprietàProperties ProprietàProperties Le proprietà devono essere conformi a un pattern di nome specifico.Properties shall adhere to a specific naming pattern. L'attributo SpecialName indicato nella regola CLS 24 deve essere ignorato nei confronti tra nomi appropriati e deve essere conforme alle regole dell'identificatore.The SpecialName attribute referred to in CLS rule 24 shall be ignored in appropriate name comparisons and shall adhere to identifier rules. Una proprietà deve disporre di un metodo Get, un metodo Set o di entrambi.A property shall have a getter method, a setter method, or both. 2828
Conversione di tipiType conversion Conversione di tipiType conversion Se viene specificato op_Implicit oppure op_Explicit, sarà necessario fornire un metodo alternativo di coercizione.If either op_Implicit or op_Explicit is provided, an alternate means of providing the coercion shall be provided. 3939
TipiTypes Tipo e firme dei membri di tipoType and type member signatures I tipi di valore boxed non sono conformi a CLS.Boxed value types are not CLS-compliant. 33
TipiTypes Tipo e firme dei membri di tipoType and type member signatures Tutti i tipi visualizzati in una firma devono essere conformi a CLS.All types appearing in a signature shall be CLS-compliant. Tutti i tipi che costituiscono un tipo generico con istanze devono essere conformi a CLS.All types composing an instantiated generic type shall be CLS-compliant. 1111
TipiTypes Tipo e firme dei membri di tipoType and type member signatures I riferimenti tipizzati non sono conformi a CLS.Typed references are not CLS-compliant. 1414
TipiTypes Tipo e firme dei membri di tipoType and type member signatures I tipi di puntatore non gestiti non sono conformi a CLS.Unmanaged pointer types are not CLS-compliant. 1717
TipiTypes Tipo e firme dei membri di tipoType and type member signatures Per le classi, i tipi di valore e le interfacce conformi a CLS non è necessaria l'implementazione di membri non conformi a CLS.CLS-compliant classes, value types, and interfaces shall not require the implementation of non-CLS-compliant members. 2020

Tipi e firme dei membri di tipoTypes and type member signatures

Il tipo System.Object è conforme a CLS ed è il tipo di base di tutti i tipi di oggetto nel sistema di tipo .NET Framework.The System.Object type is CLS-compliant and is the base type of all object types in the .NET Framework type system. L'ereditarietà in .NET Framework è implicita (ad esempio la classe String eredita in modo implicito dalla classe Object) o esplicita (ad esempio la classe CultureNotFoundException eredita in modo esplicito dalla classe ArgumentException, che eredita in modo esplicito dalla classe SystemException, che eredita in modo esplicito dalla classe Exception).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). Affinché un tipo derivato sia conforme a CLS, anche il tipo di base deve essere conforme a CLS.For a derived type to be CLS compliant, its base type must also be CLS-compliant.

Nell'esempio seguente viene illustrato un tipo derivato il cui tipo di base non è conforme a CLS.The following example shows a derived type whose base type is not CLS-compliant. Viene definita una classe Counter base tramite in cui viene usato un Unsigned Integer a 32 bit come contatore.It defines a base Counter class that uses an unsigned 32-bit integer as a counter. Poiché la classe fornisce la funzionalità contatore eseguendo il wrapping di un Unsigned Integer, la classe viene contrassegnata come non conforme a CLS.Because the class provides counter functionality by wrapping an unsigned integer, the class is marked as non-CLS-compliant. Di conseguenza, anche una classe derivata, NonZeroCounter, non è conforme a CLS.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
'                 ~~~~~~~~~~~~~~

Tutti i tipi visualizzati nelle firme dei membri, incluso il tipo restituito di un metodo o un tipo di proprietà, devono essere conformi a CLS.All types that appear in member signatures, including a method's return type or a property type, must be CLS-compliant. Inoltre, per i tipi generici:In addition, for generic types:

  • Tutti i tipi che costituiscono un tipo generico con istanze devono essere conformi a CLS.All types that compose an instantiated generic type must be CLS-compliant.

  • Tutti i tipi usati come vincoli sui parametri generici devono essere conformi a CLS.All types used as constraints on generic parameters must be CLS-compliant.

In Common Type System di .NET Framework è incluso un numero di tipi incorporati supportati direttamente da Common Language Runtime, codificati in particolare nei metadati di un assembly.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. Di questi tipi intrinseci, i tipi elencati nella tabella seguente sono conformi a CLS.Of these intrinsic types, the types listed in the following table are CLS-compliant.

Tipo conforme a CLSCLS-compliant type DESCRIZIONEDescription
Byte Unsigned Integer a 8 bit8-bit unsigned integer
Int16 Signed Integer a 16 bit16-bit signed integer
Int32 Intero con segno a 32 bit32-bit signed integer
Int64 Intero con segno a 64 bit64-bit signed integer
Single Valore a virgola mobile e precisione singolaSingle-precision floating-point value
Double Valore a virgola mobile e precisione doppiaDouble-precision floating-point value
Boolean Tipo di valore true o falsetrue or false value type
Char Unità di codice codificata UTF-16UTF-16 encoded code unit
Decimal Numero decimale non a virgola mobileNon-floating-point decimal number
IntPtr Puntatore o handle di una dimensione definita dalla piattaformaPointer or handle of a platform-defined size
String Raccolta di zero, uno o più oggetti Char.Collection of zero, one, or more Char objects

I tipi intrinseci elencati nella tabella seguente non sono conformi a CLS.The intrinsic types listed in the following table are not CLS-Compliant.

Tipo non conformeNon-compliant type DESCRIZIONEDescription Alternativa alla conformità a CLSCLS-compliant alternative
SByte Tipo di dati Signed Integer a 8 bit8-bit signed integer data type Int16
TypedReference Puntatore a un oggetto e relativo tipo di runtimePointer to an object and its runtime type nessunoNone
UInt16 Intero senza segno a 16 bit16-bit unsigned integer Int32
UInt32 Intero senza segno a 32 bit32-bit unsigned integer Int64
UInt64 Intero senza segno a 64 bit64-bit unsigned integer Int64 (possibile overflow), BigInteger o DoubleInt64 (may overflow), BigInteger, or Double
UIntPtr Puntatore o handle senza segnoUnsigned pointer or handle IntPtr

Nella libreria di classi .NET Framework o in qualsiasi altra libreria di classi possono essere inclusi altri tipi non conformi a CLS; ad esempio:The .NET Framework Class Library or any other class library may include other types that aren't CLS-compliant; for example:

  • Tipi di valore boxed.Boxed value types. Nell'esempio C# seguente viene creata una classe con una proprietà pubblica di tipo int* denominata Value.The following C# example creates a class that has a public property of type int* named Value. Poiché int* è un tipo di valore boxed, viene contrassegnato come non conforme a CLS dal compilatore.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
    
  • Riferimenti tipizzati, che sono costrutti speciali contenenti un riferimento a un oggetto e un riferimento a un tipo.Typed references, which are special constructs that contain a reference to an object and a reference to a type. I riferimenti tipizzati sono rappresentati in .NET Framework dalla classe TypedReference.Typed references are represented in the .NET Framework by the TypedReference class.

Se un tipo non è conforme a CLS, è necessario applicarvi l'attributo CLSCompliantAttribute con un valore isCompliant``false.If a type is not CLS-compliant, you should apply the CLSCompliantAttribute attribute with an isCompliant value of false to it. Per altre informazioni, vedere la sezione Attributo CLSCompliantAttribute.For more information, see The CLSCompliantAttribute attribute section.

Nell'esempio seguente viene illustrato il problema della conformità a CLS in una firma di metodo e nella creazione di un'istanza di tipo generico.The following example illustrates the problem of CLS compliance in a method signature and in generic type instantiation. Viene definita una classe InvoiceItem con una proprietà di tipo UInt32, una proprietà di tipo Nullable(Of UInt32) e un costruttore con parametri di tipo UInt32 e Nullable(Of UInt32).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). Vengono visualizzati quattro avvisi del compilatore quando si tenta di compilare l'esempio.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
'                       ~~~~~~~~~

Per eliminare gli avvisi del compilatore, sostituire i tipi non conformi a CLS nell'interfaccia pubblica InvoiceItem con tipi conformi: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

Oltre ai tipi specifici elencati, alcune categorie di tipi non sono conformi a CLS,In addition to the specific types listed, some categories of types are not CLS compliant. tra cui, tipi di puntatore non gestiti e tipi di puntatore a funzione.These include unmanaged pointer types and function pointer types. Nell'esempio seguente viene generato un avviso del compilatore perché viene usato un puntatore a un Integer per creare una matrice di Integer.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

Per le classi astratte conformi a CLS (cioè quelle contrassegnate come abstract in C# o come MustInherit in Visual Basic), anche tutti i membri della classe devono essere conformi a CLS.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.

Convenzioni di denominazioneNaming conventions

Poiché per alcuni linguaggi di programmazione non viene fatta distinzione tra maiuscole e minuscole, gli identificatori, ad esempio i nomi degli spazi dei nomi, i tipi e i membri, occorre che non differiscano solo per la combinazione di caratteri maiuscoli o minuscoli.Because some programming languages are case-insensitive, identifiers (such as the names of namespaces, types, and members) must differ by more than case. Due identificatori sono considerati equivalenti se i relativi mapping di minuscole sono uguali.Two identifiers are considered equivalent if their lowercase mappings are the same. Nell'esempio di C# seguente vengono definite due classi pubbliche, Person e person.The following C# example defines two public classes, Person and person. Poiché si differenziano solo per le maiuscole e le minuscole, dal compilatore C# vengono contrassegnate come non conformi a CLS.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)

Gli identificatori del linguaggio di programmazione, ad esempio i nomi degli spazi dei nomi, i tipi e i membri, devono essere conformi allo standard Unicode 3.0, rapporto tecnico 15, allegato 7.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. Vale a dire che:This means that:

  • Il primo carattere di un identificatore può essere qualsiasi carattere Unicode, una lettera maiuscola, una lettera minuscola, tutte iniziali maiuscole, una lettera di modificatore, un'altra lettera o un numero rappresentato dalla lettera.The first character of an identifier can be any Unicode uppercase letter, lowercase letter, title case letter, modifier letter, other letter, or letter number. Per informazioni sulle categorie di caratteri Unicode, vedere l'enumerazione System.Globalization.UnicodeCategory.For information on Unicode character categories, see the System.Globalization.UnicodeCategory enumeration.

  • I caratteri successivi possono provenire da una qualsiasi delle categorie come primo carattere e in essi possono anche essere inclusi contrassegni senza spaziatura, contrassegni di combinazioni di spazi, numeri decimali, punteggiature del connettore e codici di formattazione.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.

Prima di confrontare gli identificatori, è necessario filtrare i codici di formattazione e convertire gli identificatori nel formato di normalizzazione Unicode C, poiché un singolo carattere può essere rappresentato da più unità di codice codificate UTF-16.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. Le sequenze di caratteri che producono le stesse unità di codice nel formato di normalizzazione Unicode C non sono conformi a CLS.Character sequences that produce the same code units in Unicode Normalization Form C are not CLS-compliant. L'esempio seguente definisce una proprietà denominata , costituita dal carattere SEGNO di ANGSTROM (U+212B) e una seconda proprietà denominata Å, costituita dal carattere LETTERA LATINA A MAIUSCOLA CON UN CERCHIO SOPRA (U+00C5).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). Sia dai compilatori C# sia da quelli Visual Basic il codice sorgente viene contrassegnato come non conforme a CLS.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
'                       ~

I nomi dei membri all'interno di un ambito specifico (ad esempio gli spazi dei nomi in un assembly, i tipi in uno spazio dei nomi o i membri in un tipo) devono essere univoci ad eccezione dei nomi che vengono risolti tramite l'overload.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. Questo requisito è più rigido di quello di Common Type System, che consente a più membri all'interno di un ambito di disporre di nomi identici purché siano tipi diversi di membri (ad esempio, uno è un metodo e uno è un campo).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). In particolare, per i membri di tipo:In particular, for type members:

  • I campi e i tipi annidati vengono distinti solo in base al nome.Fields and nested types are distinguished by name alone.

  • I metodi, le proprietà e gli eventi che hanno lo stesso nome devono presentare differenze che vanno oltre il solo tipo restituito.Methods, properties, and events that have the same name must differ by more than just return type.

Nell'esempio seguente viene illustrato il requisito in base al quale i nomi dei membri devono essere univoci all'interno del relativo ambito.The following example illustrates the requirement that member names must be unique within their scope. Viene definita una classe denominata Converter in cui sono inclusi quattro membri denominati Conversion.It defines a class named Converter that includes four members named Conversion. Tre sono metodi e uno è una proprietà.Three are methods, and one is a property. Il metodo che prevede un parametro Int64 è denominato in modo univoco, ma i due metodi con un parametro Int32 non lo sono, poiché il valore restituito non è considerato parte della firma di un membro.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. Questo requisito viene violato anche dalla proprietà Conversion, poiché le proprietà non possono disporre dello stesso nome dei metodi di overload.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
'                                ~~~~~~~~~~

Nei singoli linguaggi sono incluse parole chiave univoche, pertanto i linguaggi destinati a Common Language Runtime devono fornire anche un meccanismo di riferimento agli identificatori (ad esempio nomi di tipi) che coincidono con le parole chiave.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. Ad esempio, case è una parola chiave sia in C# sia in Visual Basic.For example, case is a keyword in both C# and Visual Basic. Tuttavia, nell'esempio di Visual Basic seguente è possibile evitare ambiguità relative a una classe denominata case dalla parola chiave case usando le parentesi graffe di apertura e chiusura.However, the following Visual Basic example is able to disambiguate a class named case from the case keyword by using opening and closing braces. In caso contrario, nell'esempio verrà generato il messaggio di errore "Parola chiave non valida come identificatore" e la compilazione non verrà completata.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

Nell'esempio di C# seguente è possibile creare un'istanza della classe case usando il simbolo @ per evitare ambiguità nell'identificatore della parola chiave del linguaggio.The following C# example is able to instantiate the case class by using the @ symbol to disambiguate the identifier from the language keyword. Senza, tramite il compilatore C# verrebbero visualizzati due messaggi di errore, "È previsto un tipo" e "'case' è un termine non valido nell'espressione".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);
   }
}

Conversione di tipiType conversion

Tramite le specifiche CLS (Common Language Specification) vengono definiti due operatori di conversione:The Common Language Specification defines two conversion operators:

  • op_Implicit, che viene usato per le conversioni verso un tipo di dati più grande che non comportano la perdita di dati o di precisione.op_Implicit, which is used for widening conversions that do not result in loss of data or precision. Ad esempio, nella struttura Decimal è incluso un operatore op_Implicit di overload per convertire i valori di tipi integrali e i valori Char in valori Decimal.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, che viene usato per le conversioni verso un tipo di dati più piccolo che possono comportare la perdita di grandezza (un valore viene convertito in un altro a cui è associato un intervallo inferiore) o di precisione.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. Ad esempio, nella struttura Decimal è incluso un operatore op_Explicit di overload per convertire i valori Double e Single in Decimal e per convertire i valori Decimal in valori integrali Double, Single e Char.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.

Tuttavia, non tutti i linguaggi supportano l'overload degli operatori o la definizione di operatori personalizzati.However, not all languages support operator overloading or the definition of custom operators. Se si sceglie di implementare questi operatori di conversione, è necessario fornire anche un modo alternativo per eseguire la conversione.If you choose to implement these conversion operators, you should also provide an alternate way to perform the conversion. È consigliabile fornire i metodi FromXxx e ToXxx.We recommend that you provide FromXxx and ToXxx methods.

Nell'esempio seguente vengono definite le convenzioni esplicite e implicite conformi a CLS.The following example defines CLS-compliant implicit and explicit conversions. Viene creata una classe UDouble che rappresenta un numero a virgola mobile e precisione doppia con segno.It creates a UDouble class that represents an signed double-precision, floating-point number. Viene usato per le conversioni implicite da UDouble a Double e per le conversioni esplicite da UDouble a Single, da Double a UDouble e da Single a UDouble.It provides for implicit conversions from UDouble to Double and for explicit conversions from UDouble to Single, Double to UDouble, and Single to UDouble. Vengono anche definiti un metodo ToDouble come alternativa all'operatore di conversione implicito e i metodi ToSingle, FromDouble e FromSingle come alternative agli operatori di conversione espliciti.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

MatriciArrays

Le matrici conformi a CLS sono conformi alle regole seguenti:CLS-compliant arrays conform to the following rules:

  • Il limite inferiore di tutte le dimensioni di una matrice deve essere uguale a zero.All dimensions of an array must have a lower bound of zero. Nell'esempio seguente viene creata una matrice non conforme a CLS con un limite inferiore pari a uno.The following example creates a non-CLS-compliant array with a lower bound of one. Si noti che, nonostante la presenza dell'attributo CLSCompliantAttribute, tramite il compilatore non viene rilevato che la matrice restituita dal metodo Numbers.GetTenPrimes non è conforme a CLS.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
    
  • Tutti gli elementi delle matrici devono essere costituiti da tipi conformi a CLS.All array elements must consist of CLS-compliant types. Nell'esempio seguente vengono definiti due metodi tramite cui vengono restituite matrici non conformi a CLS.The following example defines two methods that return non-CLS-compliant arrays. Tramite il primo viene restituita una matrice di valori UInt32.The first returns an array of UInt32 values. Tramite il secondo viene restituita una matrice Object in cui sono inclusi i valori Int32 e UInt32.The second returns an Object array that includes Int32 and UInt32 values. Anche se il compilatore consente di identificare la prima matrice come non conforme a causa del relativo tipo UInt32, non è in grado di riconoscere che nella seconda matrice sono inclusi elementi non conformi a CLS.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()
    '                              ~~~~~~~~~~~~
    
  • La risoluzione dell'overload per i metodi a cui sono associati parametri di matrice è basata sul fatto che si tratta di matrici e sul relativo tipo di elemento.Overload resolution for methods that have array parameters is based on the fact that they are arrays and on their element type. Per questo motivo, la seguente definizione di un metodo GetSquares di overload è conforme a CLS.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
    

InterfacceInterfaces

Tramite interfacce conformi a CLS è possibile definire proprietà, eventi e metodi virtuali (metodi senza l'implementazione).CLS-compliant interfaces can define properties, events, and virtual methods (methods with no implementation). Un'interfaccia conforme a CLS non può disporre di uno dei seguenti valori:A CLS-compliant interface cannot have any of the following:

  • Metodi o campi statici.Static methods or static fields. Sia tramite i compilatori C# sia tramite quelli Visual Basic vengono generati errori del compilatore se si definisce un membro statico in un'interfaccia.Both the C# and Visual Basic compilers generate compiler errors if you define a static member in an interface.

  • Campi.Fields. Sia tramite i compilatori C# sia tramite quelli Visual Basic vengono generati errori del compilatore se si definisce un campo in un'interfaccia.Both the C# and Visual Basic compilers generate compiler errors if you define a field in an interface.

  • Metodi non conformi a CLS.Methods that are not CLS-compliant. Ad esempio, nella definizione dell'interfaccia seguente è incluso un metodo, INumber.GetUnsigned, che è contrassegnato come non conforme a CLS.For example, the following interface definition includes a method, INumber.GetUnsigned, that is marked as non-CLS-compliant. In questo esempio verrà generato un avviso del compilatore.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
    '                                      ~~~~~~~~~~~
    

    A causa di questa regola, i tipi conformi a CLS non sono necessari per l'implementazione di membri non conformi a CLS.Because of this rule, CLS-compliant types are not required to implement non-CLS-compliant members. Se tramite un framework conforme a CLS viene esposta una classe mediante la quale viene implementata un'interfaccia non conforme a CLS, è anche consigliabile fornire implementazioni concrete di tutti i membri non conformi a CLS.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.

I compilatori di linguaggi conformi a CLS devono anche consentire a una classe di fornire implementazioni separate di membri con lo stesso nome e la stessa firma in più interfacce.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. Sia C# sia Visual Basic supportano implementazioni di interfacce esplicite per offrire diverse implementazioni di metodi denominati in modo identico.Both C# and Visual Basic support explicit interface implementations to provide different implementations of identically named methods. Visual Basic supporta anche la parola chiave Implements, che consente di definire in modo esplicito l'interfaccia e il membro tramite cui viene implementato un particolare membro.Visual Basic also supports the Implements keyword, which enables you to explicitly designate which interface and member a particular member implements. Nell'esempio seguente viene illustrato questo scenario definendo una classe Temperature mediante la quale vengono implementate le interfacce ICelsius e IFahrenheit come implementazioni di interfacce esplicite.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

EnumerazioniEnumerations

Le enumerazioni conformi a CLS devono rispettare queste regole:CLS-compliant enumerations must follow these rules:

  • Il tipo sottostante dell'enumerazione deve essere un Integer intrinseco conforme a CLS (Byte, Int16, Int32 o Int64).The underlying type of the enumeration must be an intrinsic CLS-compliant integer (Byte, Int16, Int32, or Int64). Ad esempio, tramite il codice seguente viene eseguito il tentativo di definizione di un'enumerazione il cui tipo sottostante è UInt32 e viene generato un avviso del compilatore.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
    '                ~~~~
    
  • Un tipo di enumerazione deve avere un singolo campo di istanza denominato Value__ contrassegnato con l'attributo FieldAttributes.RTSpecialName.An enumeration type must have a single instance field named Value__ that is marked with the FieldAttributes.RTSpecialName attribute. Ciò consente di fare riferimento al valore del campo in modo implicito.This enables you to reference the field value implicitly.

  • Un'enumerazione prevede campi statici con valori letterali i cui tipi corrispondono al tipo dell'enumerazione stessa.An enumeration includes literal static fields whose types match the type of the enumeration itself. Ad esempio, se si definisce un'enumerazione State con valori State.On e State.Off, State.On e State.Off sono entrambi campi statici con valori letterali il cui tipo è State.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.

  • Vi sono due tipi di enumerazioni:There are two kinds of enumerations:

    • Enumerazione che rappresenta un set di Integer denominati che si escludono a vicenda.An enumeration that represents a set of mutually exclusive, named integer values. Questo tipo di enumerazione è indicato dall'assenza dell'attributo personalizzato System.FlagsAttribute.This type of enumeration is indicated by the absence of the System.FlagsAttribute custom attribute.

    • Enumerazione che rappresenta un set di flag di bit che possono essere combinati per generare un valore senza nome.An enumeration that represents a set of bit flags that can combine to generate an unnamed value. Questo tipo di enumerazione è indicato dalla presenza dell'attributo personalizzato System.FlagsAttribute.This type of enumeration is indicated by the presence of the System.FlagsAttribute custom attribute.

    Per ulteriori informazioni, vedere la documentazione relativa alla struttura Enum.For more information, see the documentation for the Enum structure.

  • Il valore di un'enumerazione non è limitato all'intervallo dei relativi valori specificati.The value of an enumeration is not limited to the range of its specified values. In altre parole, l'intervallo di valori in una enumerazione è l'intervallo del relativo valore sottostante.In other words, the range of values in an enumeration is the range of its underlying value. È possibile usare il metodo Enum.IsDefined per determinare se un valore specificato è un membro di un'enumerazione.You can use the Enum.IsDefined method to determine whether a specified value is a member of an enumeration.

Membri dei tipi in generaleType members in general

In base alle specifiche CLS (Common Language Specification), l'accesso a tutti i campi e metodi deve essere effettuato come membri di una classe particolare.The Common Language Specification requires all fields and methods to be accessed as members of a particular class. Pertanto, i campi e i metodi statici globali, vale a dire campi o metodi statici definiti oltre a un tipo, non sono conformi a CLS.Therefore, global static fields and methods (that is, static fields or methods that are defined apart from a type) are not CLS-compliant. Se si tenta di includere un campo o un metodo globale nel codice sorgente, viene generato un errore del compilatore sia dai compilatori C# sia da quelli Visual Basic.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.

Le specifiche CLS (Common Language Specification) supportano solo la convenzione di chiamata gestita standard.The Common Language Specification supports only the standard managed calling convention. Non supportano le convenzioni di chiamata non gestite né i metodi con elenchi di argomenti variabili contrassegnati con la parola chiave varargs.It doesn't support unmanaged calling conventions and methods with variable argument lists marked with the varargs keyword. Per gli elenchi di argomenti variabili compatibili con la convenzione di chiamata gestita standard, utilizzare l'attributo ParamArrayAttribute o l'implementazione del singolo linguaggio, ad esempio la parola chiave params in C# e la parola chiave ParamArray 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.

Accessibilità del membroMember accessibility

Tramite l'override di un membro ereditato non è possibile modificare l'accessibilità del membro in questione.Overriding an inherited member cannot change the accessibility of that member. Ad esempio, un metodo pubblico in una classe di base non può essere sottoposto a override da un metodo privato in una classe derivata.For example, a public method in a base class cannot be overridden by a private method in a derived class. Vi è un'eccezione: un membro protected internal (in C#) o Protected Friend (in Visual Basic) in un assembly sottoposto a override da un tipo in un assembly diverso.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 questo caso, l'accessibilità dell'override è Protected.In that case, the accessibility of the override is Protected.

Nell'esempio seguente viene illustrato l'errore generato quando l'attributo CLSCompliantAttribute è impostato su true e tramite Human, cioè una classe derivata da Animal, si tenta di modificare l'accessibilità della proprietà Species da pubblica a privata.The following example illustrates the error that is generated when the CLSCompliantAttribute attribute is set to true, and Human, which is a class derived from Animal, tries to change the accessibility of the Species property from public to private. L'esempio viene compilato correttamente se la relativa accessibilità è stata modificata in pubblica.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

I tipi nella firma di un membro devono essere accessibili ogni volta che il membro è accessibile.Types in the signature of a member must be accessible whenever that member is accessible. Ciò significa, ad esempio, che in un membro pubblico non può essere incluso un parametro il cui tipo è privato, protetto o interno.For example, this means that a public member cannot include a parameter whose type is private, protected, or internal. Nell'esempio seguente viene illustrato l'errore del compilatore generato quando tramite un costruttore di classe StringWrapper viene esposto un valore di enumerazione StringOperationType interno con cui si determina la modalità di esecuzione del wrapping di un valore stringa.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)
'                              ~~~~~~~~~~~~~~~~~~~

Tipi e membri genericiGeneric types and members

I tipi annidati dispongono sempre di un numero di parametri generici almeno pari a quelli del relativo tipo di inclusione.Nested types always have at least as many generic parameters as their enclosing type. Questi corrispondono per posizione ai parametri generici del tipo di inclusione.These correspond by position to the generic parameters in the enclosing type. Il tipo generico può anche prevedere nuovi parametri generici.The generic type can also include new generic parameters.

La relazione tra i parametri di tipo generico di un tipo contenitore e i relativi tipi annidati può essere nascosta dalla sintassi dei singoli linguaggi.The relationship between the generic type parameters of a containing type and its nested types may be hidden by the syntax of individual languages. Nell'esempio seguente in un tipo generico Outer<T> sono contenute due classi annidate, Inner1A e Inner1B<U>.In the following example, a generic type Outer<T> contains two nested classes, Inner1A and Inner1B<U>. Con le chiamate al metodo ToString, che ogni classe eredita da Object.ToString, viene mostrato che in ogni classe annidata sono inclusi i parametri di tipo della relativa classe che li contiene.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]

I nomi di tipo generico sono codificati nel formato nome`n, dove name è il nome del tipo, ` è un valore letterale del carattere e n è il numero di parametri dichiarati nel tipo oppure, per i tipi generici annidati, il numero di parametri di tipo appena introdotti.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. Questa codifica dei nomi di tipo generico è principalmente di interesse per gli sviluppatori che usano la reflection per accedere ai tipi generici conformi a CLS in una libreria.This encoding of generic type names is primarily of interest to developers who use reflection to access CLS-complaint generic types in a library.

Se i vincoli vengono applicati a un tipo generico, anche tutti i tipi usati come vincoli devono essere conformi a CLS.If constraints are applied to a generic type, any types used as constraints must also be CLS-compliant. Nell'esempio seguente viene definita una classe denominata BaseClass che non è conforme a CLS e una classe generica denominata BaseCollection il cui parametro di tipo deve derivare da BaseClass.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. Tuttavia, poiché BaseClass non è conforme a CLS, viene generato un avviso dal compilatore.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)
'                                        ~~~~~~~~~

Se un tipo generico è derivato da un tipo base generico, è necessario dichiarare nuovamente tutti i vincoli in modo che sia possibile garantire che vengano soddisfatti anche i vincoli sul tipo base.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. Nell'esempio riportato di seguito viene definito un oggetto Number<T> che può rappresentare qualsiasi tipo numerico.The following example defines a Number<T> that can represent any numeric type. Viene anche definita una classe FloatingPoint<T> che rappresenta un valore a virgola mobile.It also defines a FloatingPoint<T> class that represents a floating point value. Tuttavia, il codice sorgente non viene compilato, perché non viene applicato il vincolo su Number<T> (che T deve essere un tipo di valore) a FloatingPoint<T>.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)
'                                                          ~

L'esempio viene compilato correttamente se il vincolo viene aggiunto alla classe FloatingPoint<T>.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           

Le specifiche CLS (Common Language Specification) impongono un modello conservativo per creazione di istanze per tipi annidati e membri protetti.The Common Language Specification imposes a conservative per-instantiation model for nested types and protected members. Tramite i tipi generici aperti non è possibile esporre campi o membri con firme contenenti la creazione di un'istanza specifica di un tipo generico annidato e protetto.Open generic types cannot expose fields or members with signatures that contain a specific instantiation of a nested, protected generic type. Tramite i tipi non generici, mediante i quali viene estesa la creazione di un'istanza specifica di un'interfaccia o di una classe di base generica, non è possibile esporre i campi o i membri con firme contenenti la creazione di un'istanza differente di un tipo generico annidato e protetto.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.

Nell'esempio seguente vengono definiti un tipo generico, C1<T> (o C1(Of T) in Visual Basic) e una classe protetta, C1<T>.N (o C1(Of T).N in Visual Basic).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). L'oggetto C1<T> dispone di due metodi: M1 e M2.C1<T> has two methods, M1 and M2. Tuttavia, M1 non è conforme a CLS poiché tramite esso si tenta di restituire un oggetto C1<int>.N (o C1(Of Integer).N) da C1<T> (o C1(Of T)).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)). Una seconda classe, C2, viene derivata da C1<long> (o C1(Of Long)).A second class, C2, is derived from C1<long> (or C1(Of Long)). Dispone di due metodi, M3 e M4.It has two methods, M3 and M4. M3 non è conforme a CLS poiché viene eseguito il tentativo di restituzione di un oggetto C1<int>.N (o C1(Of Integer).N) da una sottoclasse di C1<long>.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>. Si noti che i compilatori di linguaggio possono essere anche più restrittivi.Note that language compilers can be even more restrictive. In questo esempio in Visual Basic viene visualizzato un errore quando viene eseguito un tentativo di compilazione di M4.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)  
'                             ~~~~~~~~~~~~~

CostruttoriConstructors

I costruttori nelle classi e strutture conformi a CLS devono rispettare queste regole:Constructors in CLS-compliant classes and structures must follow these rules:

  • Prima di accedere ai dati di istanza ereditati, un costruttore di una classe derivata deve chiamare il costruttore di istanze della relativa classe di base.A constructor of a derived class must call the instance constructor of its base class before it accesses inherited instance data. Questo requisito è dovuto al fatto che i costruttori della classe di base non vengono ereditati dalle classi derivate.This requirement is due to the fact that base class constructors are not inherited by their derived classes. Questa regola non si applica alle strutture, che non supportano l'ereditarietà diretta.This rule does not apply to structures, which do not support direct inheritance.

    In genere, questa regola viene applicata dai compilatori indipendentemente dalla conformità a CLS, come illustrato dall'esempio riportato di seguito.Typically, compilers enforce this rule independently of CLS compliance, as the following example shows. Viene creata una classe Doctor derivata da una classe Person, ma la classe Doctor non riuscirà a chiamare il costruttore della classe Person per inizializzare i campi di istanza ereditati.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()
    '                  ~~~
    
  • Il costruttore di un oggetto non può essere chiamato tranne che per creare un oggetto.An object constructor cannot be called except to create an object. Inoltre, un oggetto non può essere inizializzato due volte.In addition, an object cannot be initialized twice. Ciò significa, ad esempio, che tramite i metodi Object.MemberwiseClone e di deserializzazione come BinaryFormatter.Deserialize non devono essere chiamati i costruttori.For example, this means that Object.MemberwiseClone and deserialization methods such as BinaryFormatter.Deserialize must not call constructors.

ProprietàProperties

Le proprietà nei tipi conformi a CLS devono rispettare queste regole:Properties in CLS-compliant types must follow these rules:

  • Una proprietà deve disporre di un metodo Set, un metodo Get o di entrambi.A property must have a setter, a getter, or both. In un assembly questi vengono implementati come metodi speciali, ovvero vengono visualizzati come metodi separati (getter è denominato get_nomeproprietà e setter è set_nomeproprietà) contrassegnati come SpecialName nei metadati dell'assembly.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. Tramite i compilatori C# e Visual Basic questa regola viene applicata automaticamente senza la necessità di utilizzare l'attributo CLSCompliantAttribute.The C# and Visual Basic compilers enforce this rule automatically without the need to apply the CLSCompliantAttribute attribute.

  • Un tipo di proprietà è il tipo restituito del metodo Get della proprietà e l'ultimo argomento del metodo Set.A property's type is the return type of the property getter and the last argument of the setter. È necessario che questi tipi siano conformi a CLS e gli argomenti non possono essere assegnati alla proprietà per riferimento, cioè non possono essere puntatori gestiti.These types must be CLS compliant, and arguments cannot be assigned to the property by reference (that is, they cannot be managed pointers).

  • Se una proprietà dispone dei metodi Get e Set, essi devono essere entrambi virtuali, statici o istanze.If a property has both a getter and a setter, they must both be virtual, both static, or both instance. Dai compilatori C# e Visual Basic questa regola viene applicata automaticamente tramite la relativa sintassi di definizione della proprietà.The C# and Visual Basic compilers automatically enforce this rule through their property definition syntax.

EventiEvents

Un evento viene definito in base al nome e al relativo tipo.An event is defined by its name and its type. Il tipo di evento è un delegato che viene usato per indicare l'evento.The event type is a delegate that is used to indicate the event. Ad esempio, l'evento AppDomain.AssemblyResolve è di tipo ResolveEventHandler.For example, the AppDomain.AssemblyResolve event is of type ResolveEventHandler. Oltre all'evento stesso, vi sono tre metodi con nomi basati sul nome di evento che forniscono l'implementazione dell'evento e sono contrassegnati come SpecialName nei metadati dell'assembly: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:

  • Un metodo per l'aggiunta di un gestore eventi, denominato add_EventName.A method for adding an event handler, named add_EventName. Ad esempio, il metodo di sottoscrizione evento per l'evento AppDomain.AssemblyResolve è denominato add_AssemblyResolve.For example, the event subscription method for the AppDomain.AssemblyResolve event is named add_AssemblyResolve.

  • Un metodo per la rimozione di un gestore eventi, denominato remove_EventName.A method for removing an event handler, named remove_EventName. Ad esempio, il metodo di rimozione per l'evento AppDomain.AssemblyResolve è denominato remove_AssemblyResolve.For example, the removal method for the AppDomain.AssemblyResolve event is named remove_AssemblyResolve.

  • Un metodo per indicare che si è verificato l'evento, denominato raise_EventName.A method for indicating that the event has occurred, named raise_EventName.

Nota

La maggior parte delle regole di Common Language Specification relative agli eventi viene implementata dai compilatori di linguaggi e risulta trasparente agli sviluppatori di componenti.Most of the Common Language Specification's rules regarding events are implemented by language compilers and are transparent to component developers.

I metodi per l'aggiunta, la rimozione e la generazione di eventi devono avere la stessa accessibilità.The methods for adding, removing, and raising the event must have the same accessibility. Devono anche essere tutti statici, istanze o virtuali.They must also all be static, instance, or virtual. I metodi per l'aggiunta e la rimozione di un evento dispongono di un parametro il cui tipo è il tipo delegato di evento.The methods for adding and removing an event have one parameter whose type is the event delegate type. I metodi di aggiunta e rimozione devono essere entrambi presenti o entrambi assenti.The add and remove methods must both be present or both be absent.

Nell'esempio seguente viene definita una classe conforme a CLS denominata Temperature tramite cui viene generato un evento TemperatureChanged se la modifica nella temperatura tra due letture è uguale o maggiore di un valore soglia.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. Tramite la classe Temperature viene definito in modo esplicito un metodo raise_TemperatureChanged in modo che tramite esso sia possibile eseguire selettivamente i gestori eventi.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

Le specifiche CLS (Common Language Specification) impongono i requisiti seguenti sui membri di overload:The Common Language Specification imposes the following requirements on overloaded members:

  • I membri possono essere sottoposti a overload in base al numero di parametri e al tipo di qualsiasi parametro.Members can be overloaded based on the number of parameters and the type of any parameter. La convenzione di chiamata, il tipo restituito, i modificatori personalizzati applicati al metodo o al relativo parametro e se i parametri vengono passati per valore o per riferimento vengono ignorati quando viene fatta distinzione tra gli overload.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. Per un esempio, vedere il codice relativo al requisito in cui viene richiesto che i nomi siano univoci all'interno di un ambito nella sezione Convenzioni di denominazione.For an example, see the code for the requirement that names must be unique within a scope in the Naming conventions section.

  • È possibile eseguire l'overload solo di proprietà e metodi.Only properties and methods can be overloaded. Non è possibile eseguire l'overload di campi ed eventi.Fields and events cannot be overloaded.

  • I metodi generici possono essere sottoposti a overload in base al numero dei relativi parametri generici.Generic methods can be overloaded based on the number of their generic parameters.

Nota

Gli operatori op_Explicit e op_Implicit sono eccezioni alla regola che il valore restituito non viene considerato parte di una firma del metodo per risoluzione dell'overload.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. Questi due operatori possono essere sottoposti a overload in base ai relativi parametri e al relativo valore restituito.These two operators can be overloaded based on both their parameters and their return value.

EccezioniExceptions

Gli oggetti eccezione devono derivare da System.Exception o da un altro tipo derivato da System.Exception.Exception objects must derive from System.Exception or from another type derived from System.Exception. Nell'esempio seguente viene illustrato l'errore del compilatore generato quando una classe personalizzata denominata ErrorClass viene usata per la gestione delle eccezioni.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
'             ~~~~~~~~~~~~~~

Per correggere questo errore, la classe ErrorClass deve ereditare da System.Exception.To correct this error, the ErrorClass class must inherit from System.Exception. Inoltre, la proprietà Message deve essere sottoposta a override.In addition, the Message property must be overridden. Nell'esempio riportato di seguito questi errori vengono corretti per definire una classe ErrorClass che è conforme a CLS.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

AttributiAttributes

Negli assembly .NET Framework, gli attributi personalizzati forniscono un meccanismo estensibile per archiviare gli attributi personalizzati e recuperare i metadati sugli oggetti di programmazione, ad esempio assembly, tipi, membri e parametri di metodo.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. Gli attributi personalizzati devono derivare da System.Attribute o da un tipo derivato da System.Attribute.Custom attributes must derive from System.Attribute or from a type derived from System.Attribute.

Nell'esempio riportato di seguito viene violata questa regola.The following example violates this rule. Viene definita una classe NumericAttribute che non deriva da System.Attribute.It defines a NumericAttribute class that does not derive from System.Attribute. Si noti che un errore del compilatore viene visualizzato solo quando viene applicato l'attributo non conforme a CLS, non quando la classe è definita.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
'     ~~~~~~~~~~~~~

Tramite il costruttore o le proprietà di un attributo conforme a CLS possono essere esposti solo i tipi seguenti:The constructor or the properties of a CLS-compliant attribute can expose only the following types:

Nell'esempio seguente viene definita una DescriptionAttribute classe che deriva da Attribute.The following example defines a DescriptionAttribute class that derives from Attribute. Il costruttore di classe dispone di un parametro di tipo Descriptor, pertanto la classe non è conforme a CLS.The class constructor has a parameter of type Descriptor, so the class is not CLS-compliant. Si noti che tramite il compilatore C# viene generato un avviso ma l'operazione di compilazione viene eseguita correttamente, mentre tramite il compilatore Visual Basic non vengono generati né avvisi, né errori.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

Attributo CLSCompliantAttributeThe CLSCompliantAttribute attribute

L'attributo CLSCompliantAttribute è utilizzato per indicare se un elemento del programma è conforme a CLS (Common Language Specification).The CLSCompliantAttribute attribute is used to indicate whether a program element complies with the Common Language Specification. Nel costruttore CLSCompliantAttribute.CLSCompliantAttribute(Boolean) è incluso un solo parametro obbligatorio, isCompliant, che indica se l'elemento del programma è conforme a CLS.The CLSCompliantAttribute.CLSCompliantAttribute(Boolean) constructor includes a single required parameter, isCompliant, that indicates whether the program element is CLS-compliant.

In fase di compilazione, tramite il compilatore vengono rilevati gli elementi non conformi che si presuppone siano conformi a CLS e viene generato un avviso.At compile time, the compiler detects non-compliant elements that are presumed to be CLS-compliant and emits a warning. Tramite il compilatore non vengono generati avvisi per i tipi o i membri che vengono dichiarati esplicitamente come non conformi.The compiler does not emit warnings for types or members that are explicitly declared to be non-compliant.

Gli sviluppatori di componenti possono usare l'attributo CLSCompliantAttribute in due modi:Component developers can use the CLSCompliantAttribute attribute in two ways:

  • Per definire le parti dell'interfaccia pubblica esposte da un componente che sono conformi a CLS e le parti che non sono conformi a CLS.To define the parts of the public interface exposed by a component that are CLS-compliant and the parts that are not CLS-compliant. Quando l'attributo viene usato per contrassegnare determinati elementi del programma come conformi a CLS, il relativo uso garantisce che gli elementi sono accessibili da tutti i linguaggi e strumenti destinati a .NET Framework.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.

  • Per assicurarsi che tramite l'interfaccia pubblica della libreria componenti vengano esposti solo elementi del programma che sono conformi a CLS.To ensure that the component library's public interface exposes only program elements that are CLS-compliant. Se gli elementi non sono conformi a CLS, tramite i compilatori viene di solito generato un avviso.If elements are not CLS-compliant, compilers will generally issue a warning.

Avviso

In alcuni casi, dai compilatori di linguaggio vengono applicate regole conformi a CLS indipendentemente dal fatto che l'attributo CLSCompliantAttribute venga usato.In some cases, language compilers enforce CLS-compliant rules regardless of whether the CLSCompliantAttribute attribute is used. Ad esempio, con la definizione di un membro statico in un'interfaccia viene violata una regola CLS.For example, defining a static member in an interface violates a CLS rule. Se si definisce un membro static (in C#) o Shared (in Visual Basic) in un'interfaccia, entrambi i compilatori C# e Visual Basic visualizzano un messaggio di errore e la compilazione dell'app non riesce.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.

L'attributo CLSCompliantAttribute è contrassegnato con un attributo AttributeUsageAttribute con un valore pari a AttributeTargets.All.The CLSCompliantAttribute attribute is marked with an AttributeUsageAttribute attribute that has a value of AttributeTargets.All. Con questo valore è possibile applicare l'attributo CLSCompliantAttribute a qualsiasi elemento del programma, tra cui assembly, moduli, tipi (classi, strutture, enumerazioni, interfacce e delegati), membri di tipo (costruttori, metodi, proprietà, campi ed eventi), parametri, parametri generici e valori restituiti.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. Tuttavia, in pratica, è consigliabile applicare l'attributo solo agli assembly, ai tipi e ai membri di tipo.However, in practice, you should apply the attribute only to assemblies, types, and type members. In caso contrario, tramite i compilatori viene ignorato l'attributo e viene continuata la generazione di avvisi del compilatore ogni volta che viene rilevato un parametro non conforme, un parametro generico o un valore restituito nell'interfaccia pubblica della libreria.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.

Il valore dell'attributo CLSCompliantAttribute viene ereditato dagli elementi del programma contenuti.The value of the CLSCompliantAttribute attribute is inherited by contained program elements. Ad esempio, se un assembly è contrassegnato come conforme a CLS, anche i relativi tipi sono conformi a CLS.For example, if an assembly is marked as CLS-compliant, its types are also CLS-compliant. Se un tipo è contrassegnato come conforme a CLS, anche i relativi membri e tipi annidati sono conformi a CLS.If a type is marked as CLS-compliant, its nested types and members are also CLS-compliant.

È possibile eseguire l'override in modo esplicito della conformità ereditata applicando l'attributo CLSCompliantAttribute a un elemento del programma contenuto.You can explicitly override the inherited compliance by applying the CLSCompliantAttribute attribute to a contained program element. Ad esempio, è possibile utilizzare l'attributo CLSCompliantAttribute con un valore isCompliant``false per definire un tipo non conforme in un assembly conforme e l'attributo con un valore isCompliant``true per definire un tipo conforme in un assembly non conforme.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. È anche possibile definire i membri non conformi in un tipo conforme.You can also define non-compliant members in a compliant type. Tuttavia, in un tipo non conforme non possono essere inclusi membri conformi, pertanto non è possibile usare l'attributo con un valore isCompliant true per eseguire l'override dell'ereditarietà da un tipo non conforme.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.

Quando si sviluppano componenti, è sempre consigliabile usare l'attributo CLSCompliantAttribute per indicare se l'assembly e i relativi tipi e membri sono conformi a CLS.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.

Per creare componenti conformi a CLS:To create CLS-compliant components:

  1. Usare l'oggetto CLSCompliantAttribute per contrassegnare l'assembly come conforme a CLS.Use the CLSCompliantAttribute to mark you assembly as CLS-compliant.

  2. Contrassegnare tutti i tipi esposti pubblicamente nell'assembly che non sono conformi a CLS come non conformi.Mark any publicly exposed types in the assembly that are not CLS-compliant as non-compliant.

  3. Contrassegnare tutti i membri esposti pubblicamente in tipi conformi a CLS come non conformi.Mark any publicly exposed members in CLS-compliant types as non-compliant.

  4. Fornire un'alternativa conforme a CLS per i membri non conformi a CLS.Provide a CLS-compliant alternative for non-CLS-compliant members.

Se sono stati contrassegnati correttamente tutti i tipi e i membri non conformi, tramite il compilatore non vengono generati avvisi di mancata conformità.If you've successfully marked all your non-compliant types and members, your compiler should not emit any non-compliance warnings. Tuttavia, è consigliabile indicare i membri che non sono conformi a CLS ed elencare le alternative conformi a CLS nella documentazione del prodotto.However, you should indicate which members are not CLS-compliant and list their CLS-compliant alternatives in your product documentation.

Nell'esempio seguente viene usato l'attributo CLSCompliantAttribute per definire un assembly conforme a CLS e un tipo, CharacterUtilities, contenente due membri non conformi a CLS.The following example uses the CLSCompliantAttribute attribute to define a CLS-compliant assembly and a type, CharacterUtilities, that has two non-CLS-compliant members. Poiché entrambi i membri sono contrassegnati con l'attributo CLSCompliant(false), non vengono generati avvisi dal compilatore.Because both members are tagged with the CLSCompliant(false) attribute, the compiler produces no warnings. La classe fornisce anche un'alternativa conforme a CLS per entrambi i metodi.The class also provides a CLS-compliant alternative for both methods. In genere, si aggiungono solo due overload al metodo ToUTF16 per fornire alternative conformi a CLS.Ordinarily, we would just add two overloads to the ToUTF16 method to provide CLS-compliant alternatives. Tuttavia, poiché i metodi non possono essere sottoposti a overload in base al valore restituito, i nomi dei metodi conformi a CLS sono diversi da quelli dei metodi non conformi.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

Se si sta sviluppando un'applicazione anziché una libreria (cioè se non si stanno esponendo tipi o membri che possono essere usati da altri sviluppatori dell'applicazione), la conformità a CLS degli elementi del programma usati dall'applicazione è importante solo se il linguaggio non li supporta.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 questo caso, tramite il compilatore di linguaggio verrà generato un errore quando si tenta di usare un elemento non conforme a CLS.In that case, your language compiler will generate an error when you try to use a non-CLS-compliant element.

Interoperabilità tra linguaggi diversiCross-Language Interoperability

L'indipendenza del linguaggio ha numerosi significati possibili.Language independence has a number of possible meanings. Un significato, illustrato nell'articolo Indipendenza del linguaggio e componenti indipendenti dal linguaggio, riguarda l'uso semplice dei tipi scritti in un linguaggio da parte di un'applicazione scritta in un linguaggio diverso.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. Un secondo significato, che è il fulcro di questo articolo, riguarda la combinazione di codice scritto in più linguaggi in un unico assembly .NET Framework.A second meaning, which is the focus of this article, involves combining code written in multiple languages into a single .NET Framework assembly.

L'esempio seguente illustra l'interoperabilità tra linguaggi mediante la creazione di una libreria di classi denominata Utilities.dll che comprende due classi, NumericLib e StringLib.The following example illustrates cross-language interoperability by creating a class library named Utilities.dll that includes two classes, NumericLib and StringLib. La classe NumericLib è scritta in C# e la classe StringLib in Visual Basic.The NumericLib class is written in C#, and the StringLib class is written in Visual Basic. Di seguito è riportato il codice sorgente per StringUtil.vb in cui è incluso un singolo membro, ToTitleCase, nella classe 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

Di seguito è riportato il codice sorgente per NumberUtil.cs tramite cui viene definita una classe NumericLib in cui sono contenuti due membri, IsEven e 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; 
   }
}

Per includere le due classi in un singolo assembly, è necessario compilarle in moduli.To package the two classes in a single assembly, you must compile them into modules. Per compilare il file di codice sorgente di Visual Basic in un modulo, usare il comando seguente:To compile the Visual Basic source code file into a module, use this command:

vbc /t:module StringUtil.vb

Per altre informazioni sulla sintassi della riga di comando del compilatore Visual Basic, vedere Compilazione dalla riga di comando.For more information about the command-line syntax of the Visual Basic compiler, see Building from the Command Line.

Per compilare il file di codice sorgente di C# in un modulo, usare il comando seguente:To compile the C# source code file into a module, use this command:

csc /t:module NumberUtil.cs

Per altre informazioni sulla sintassi della riga di comando del compilatore C#, vedere Compilazione dalla riga di comando con csc.exe.For more information about the command-line syntax of the C# compiler, see Command-line Building With csc.exe.

Usare quindi le opzioni del linker per compilare i due moduli in un assembly:You then use the Linker options to compile the two modules into an assembly:

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

L'esempio seguente chiama quindi i metodi NumericLib.NearZero e StringLib.ToTitleCase.The following example then calls the NumericLib.NearZero and StringLib.ToTitleCase methods. Sia il codice Visual Basic che il codice C# sono in grado di accedere ai metodi in entrambe le classi.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

Per compilare il codice Visual Basic, usare il comando seguente:To compile the Visual Basic code, use this command:

vbc example.vb /r:UtilityLib.dll

Per eseguire la compilazione con C#, modificare il nome del compilatore da vbc a csc e modificare l'estensione del file da vb a 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

Vedere ancheSee also