Independência da linguagem e componentes independentes da linguagemLanguage Independence and Language-Independent Components

O .NET Framework independe da linguagem.The .NET Framework is language independent. Isso significa que, como desenvolvedor, você pode desenvolver em uma das muitas linguagens que segmentam o .NET Framework, como 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. É possível acessar os tipos e os membros das bibliotecas de classes desenvolvidas para o .NET Framework sem que seja necessário conhecer a linguagem em que foram originalmente gravados e sem precisar seguir as convenções da linguagem original.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 você for um desenvolvedor de componentes, o componente poderá ser acessado por qualquer aplicativo do .NET Framework, independentemente da linguagem.If you are a component developer, your component can be accessed by any .NET Framework app regardless of its language.

Observação

A primeira parte deste artigo discorre sobre a criação de componentes independentes de linguagem, ou seja, componentes que podem ser consumidos por aplicativos escritos em qualquer linguagem.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. Você também pode criar um único componente ou aplicativo de código-fonte gravado em várias linguagens; consulte Interoperabilidade em qualquer idioma na segunda parte deste artigo.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.

Para interagir completamente com outros objetos gravados em qualquer linguagem, os objetos devem expor aos chamadores somente os recursos comuns a todas as linguagens.To fully interact with other objects written in any language, objects must expose to callers only those features that are common to all languages. Esse conjunto comum de recursos é definido pela CLS (Common Language Specification), que é um conjunto de regras que se aplicam aos assemblies gerados.This common set of features is defined by the Common Language Specification (CLS), which is a set of rules that apply to generated assemblies. A Common Language Specification é definida na Partição I, cláusulas 7 a 11 do Padrão ECMA-335: 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 o componente estiver de acordo com a Common Language Specification, ele será compatível com a CLS e poderá ser acessado pelo código em assemblies gravados em qualquer linguagem de programação que dê suporte a 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. É possível determinar se o componente está de acordo com a Common Language Specification no tempo de compilação aplicando-se o atributo CLSCompliantAttribute ao código-fonte.You can determine whether your component conforms to the Common Language Specification at compile time by applying the CLSCompliantAttribute attribute to your source code. Para obter mais informações, consulte O atributo CLSCompliantAttribute.For more information, see The CLSCompliantAttribute attribute.

Neste artigo:In this article:

Regras de conformidade com CLSCLS compliance rules

Esta seção discute as regras para criar um componente compatível com CLS.This section discusses the rules for creating a CLS-compliant component. Para obter uma lista completa de regras, confira a Partição I, Cláusula 11 do Padrão ECMA-335: Common Language Infrastructure.For a complete list of rules, see Partition I, Clause 11 of the ECMA-335 Standard: Common Language Infrastructure.

Observação

A Common Language Specification aborda cada regra de conformidade com CLS à medida que se aplica a consumidores (desenvolvedores que estão acessando programaticamente um componente compatível com CLS), estruturas (desenvolvedores que estão usando um compilador de linguagem para criar bibliotecas compatíveis com CLS) e extensores (desenvolvedores que estão criando uma ferramenta, como um compilador de linguagem ou um analisador de código que cria componentes compatíveis com 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). Este artigo enfoca as regras que se aplicam às estruturas.This article focuses on the rules as they apply to frameworks. Entretanto, algumas das regras que se aplicam a extensores também podem ser aplicadas a assemblies criados usando-se Reflection.Emit.Note, though, that some of the rules that apply to extenders may also apply to assemblies that are created using Reflection.Emit.

Para criar um componente independente de linguagem, você só precisa aplicar as regras de compatibilidade com CLS à interface pública do 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. A implementação privada não precisa estar de acordo com a especificação.Your private implementation does not have to conform to the specification.

Importante

As regras de conformidade com CLS só se aplicam à interface pública de um componente e não à implementação privada.The rules for CLS compliance apply only to a component's public interface, not to its private implementation.

Por exemplo, inteiros sem sinal que não sejam Byte não são compatíveis com CLS.For example, unsigned integers other than Byte are not CLS-compliant. Como a classe Person no exemplo a seguir expõe uma propriedade Age de tipo UInt16, o código a seguir exibe um aviso do compilador.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
'                                ~~~

É possível tornar a classe Person compatível com CLS alternado-se o tipo de propriedade Age de UInt16 para Int16, que é um inteiro com sinal 16 bits compatível com 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. Não é necessário alterar o tipo do campo personAge privado.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

A interface pública de uma biblioteca consiste no seguinte:A library's public interface consists of the following:

  • Definições de classes públicas.Definitions of public classes.

  • Definições dos membros públicos de classes públicas e definições de membros acessíveis para classes derivadas (ou seja, membros protegidos).Definitions of the public members of public classes, and definitions of members accessible to derived classes (that is, protected members).

  • Parâmetros e tipos de retorno de métodos públicos de classes públicas e parâmetros e tipos de retorno de métodos acessíveis para classes derivadas.Parameters and return types of public methods of public classes, and parameters and return types of methods accessible to derived classes.

As regras de conformidade com CLS estão listadas na tabela a seguir.The rules for CLS compliance are listed in the following table. O texto das regras foi retirado palavra por palavra do Padrão ECMA-335: Common Language Infrastructure, com direitos autorais de 2012 da 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. Informações mais detalhadas sobre essas regras são encontradas nas seções a seguir.More detailed information about these rules is found in the following sections.

CategoriaCategory ConsulteSee RegraRule Número da regraRule number
AcessibilidadeAccessibility Acessibilidade de membroMember accessibility A acessibilidade não deverá ser alterada ao substituir métodos herdados, exceto na substituição de um método herdado de um assembly diferente com acessibilidade 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. Nesse caso, a substituição deverá ter a acessibilidade family.In this case, the override shall have accessibility family. 1010
AcessibilidadeAccessibility Acessibilidade de membroMember accessibility A visibilidade e a acessibilidade de tipos e membros deverão ser de tal forma que os tipos na assinatura de qualquer membro sejam visíveis e acessíveis sempre que o próprio membro estiver visível e acessível.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. Por exemplo, um método público visível fora do assembly não deve ter um argumento cujo tipo seja visível somente dentro do 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. A visibilidade e a acessibilidade dos tipos que compõem um tipo genérico instanciado usado na assinatura de qualquer membro deverão estar visíveis e acessíveis sempre que o próprio membro estiver visível e acessível.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. Por exemplo, um tipo genérico instanciado presente na assinatura de um membro visível fora do assembly não deverá ter um argumento genérico cujo tipo seja visível somente dentro do 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
MatrizesArrays MatrizesArrays As matrizes deverão ter elementos com um tipo compatível com CLS e todas as dimensões da matriz deverão ter limites inferiores iguais a zero.Arrays shall have elements with a CLS-compliant type, and all dimensions of the array shall have lower bounds of zero. Se o item for uma matriz, o tipo do elemento da matriz será necessário para diferenciar as sobrecargas.Only the fact that an item is an array and the element type of the array shall be required to distinguish between overloads. Quando a sobrecarga é baseada em dois ou mais tipos de matriz, os tipos de elemento deverão ser chamados de tipos.When overloading is based on two or more array types the element types shall be named types. 1616
AtributosAttributes AtributosAttributes Os atributos deverão ser do tipo System.Attribute ou de um tipo que o herde.Attributes shall be of type System.Attribute, or a type inheriting from it. 4141
AtributosAttributes AtributosAttributes A CLS só permite um subconjunto das codificações de atributos personalizados.The CLS only allows a subset of the encodings of custom attributes. Os únicos tipos que deverão ser exibidos nessas codificações são (consulte a Partição IV): System.Type, System.String, System.Char, System.Boolean, System.Byte, System.Int16, System.Int32, System.Int64, System.Single, System.Double e qualquer tipo de enumeração baseado em um tipo inteiro de base compatível com 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
AtributosAttributes AtributosAttributes A CLS não permite modificadores obrigatórios visíveis publicamente (modreq, consulte a Partição II), mas permite modificadores opcionais (modopt, consulte a Partição II) que ela não entende.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
ConstrutoresConstructors ConstrutoresConstructors Um construtor de objeto deverá chamar um construtor de instância de sua classe base antes de qualquer acesso aos dados da instância herdados.An object constructor shall call some instance constructor of its base class before any access occurs to inherited instance data. (Isso não se aplica a tipos de valor, que não precisam ter construtores.)(This does not apply to value types, which need not have constructors.) 2121
ConstrutoresConstructors ConstrutoresConstructors Um construtor de objeto não deverá ser chamado, exceto como parte da criação de um objeto e um objeto não deve ser inicializado duas vezes.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
EnumeraçõesEnumerations EnumeraçõesEnumerations O tipo subjacente de um enum deverá ser um tipo de inteiro CLS interno, o nome do campo deverá ser "value__", e esse campo deverá ser marcado como 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
EnumeraçõesEnumerations EnumeraçõesEnumerations Há dois tipos diferentes de enums, indicados pela presença ou pela ausência do atributo personalizado System.FlagsAttribute (consulte a Biblioteca da Partição IV).There are two distinct kinds of enums, indicated by the presence or absence of the System.FlagsAttribute (see Partition IV Library) custom attribute. Um representa valores de inteiro nomeados; o outro representa sinalizadores de bit nomeados que podem ser combinados para gerar um valor sem nome.One represents named integer values; the other represents named bit flags that can be combined to generate an unnamed value. O valor de um enum não está limitado aos valores especificados.The value of an enum is not limited to the specified values. 88
EnumeraçõesEnumerations EnumeraçõesEnumerations Campos estáticos de literais de um enum deverão ter o tipo do próprio enum.Literal static fields of an enum shall have the type of the enum itself. 99
EventosEvents EventosEvents Os métodos que implementam um evento deverão ser marcados como SpecialName nos metadados.The methods that implement an event shall be marked SpecialName in the metadata. 2929
EventosEvents EventosEvents A acessibilidade de um evento e de seus acessadores deverá ser idêntica.The accessibility of an event and of its accessors shall be identical. 3030
EventosEvents EventosEvents Os métodos add e remove de um evento deverão estar presentes ou ausentes.The add and remove methods for an event shall both either be present or absent. 3131
EventosEvents EventosEvents Os métodos add e remove de um evento deverão utilizar um parâmetro cada um cujo tipo define o tipo do evento, e ele deverá ser derivado de 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
EventosEvents EventosEvents Os eventos deverão respeitar um padrão de nomenclatura específico.Events shall adhere to a specific naming pattern. O atributo SpecialName mencionado na regra 29 da CLS deverá ser ignorado em comparações de nome apropriadas e respeitar as regras do identificador.The SpecialName attribute referred to in CLS rule 29 shall be ignored in appropriate name comparisons and shall adhere to identifier rules. 3333
ExceçõesExceptions ExceçõesExceptions Os atributos acionados deverão ser do tipo System.Exception ou de um tipo herdado dele.Objects that are thrown shall be of type System.Exception or a type inheriting from it. Mesmo assim, os métodos compatíveis com CLS não precisam bloquear a propagação de outros tipos de exceção.Nonetheless, CLS-compliant methods are not required to block the propagation of other types of exceptions. 4040
GeralGeneral Conformidade com CLS: as RegrasCLS compliance: the Rules As regras CLS só se aplicam a essas partes de um tipo acessíveis ou visíveis fora do assembly de definição.CLS rules apply only to those parts of a type that are accessible or visible outside of the defining assembly. 11
GeralGeneral Conformidade com CLS: as RegrasCLS compliance: the Rules Membros de tipos incompatíveis com CLS não deverão ser marcados como compatíveis com CLS.Members of non-CLS compliant types shall not be marked CLS-compliant. 22
GenéricosGenerics Tipos e membros genéricosGeneric types and members Os tipos aninhados deverão ter, pelo menos, tantos parâmetros genéricos quanto o tipo delimitador.Nested types shall have at least as many generic parameters as the enclosing type. Os parâmetros genéricos em um tipo aninhado correspondem, por posição, aos parâmetros genéricos no tipo delimitador.Generic parameters in a nested type correspond by position to the generic parameters in its enclosing type. 4242
GenéricosGenerics Tipos e membros genéricosGeneric types and members O nome de um tipo genérico deverá codificar o número de parâmetros de tipo declarados no tipo não aninhado ou recém-introduzidos no tipo, se aninhado, de acordo com as regras definidas anteriormente.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
GenéricosGenerics Tipos e membros genéricosGeneric types and members Um tipo genérico deverá redeclarar restrições suficientes para assegurar que todas as restrições no tipo base ou nas interfaces sejam atendidas pelas restrições de tipo genérico.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
GenéricosGenerics Tipos e membros genéricosGeneric types and members Tipos usados como restrições em parâmetros genéricos deverão ser compatíveis com CLS.Types used as constraints on generic parameters shall themselves be CLS-compliant. 4545
GenéricosGenerics Tipos e membros genéricosGeneric types and members A visibilidade e a acessibilidade de membros (incluindo tipos aninhados) em um tipo genérico instanciado deverão ser consideradas no escopo da instanciação específica, em vez da declaração de tipo genérico como um todo.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. Supondo isso, as regras de visibilidade e acessibilidade da regra 12 da CLS continuam sendo aplicáveis.Assuming this, the visibility and accessibility rules of CLS rule 12 still apply. 4646
GenéricosGenerics Tipos e membros genéricosGeneric types and members Para cada método genérico abstrato ou virtual, deverá haver uma implementação concreta (não abstrata) padrão.For each abstract or virtual generic method, there shall be a default concrete (non-abstract) implementation. 4747
InterfacesInterfaces InterfacesInterfaces As interfaces em conformidade com CLS não deverão exigir a definição de métodos incompatíveis com CLS para implementá-los.CLS-compliant interfaces shall not require the definition of non-CLS compliant methods in order to implement them. 1818
InterfacesInterfaces InterfacesInterfaces As interfaces compatíveis com CLS não deverão definir métodos estáticos, nem devem definir campos.CLS-compliant interfaces shall not define static methods, nor shall they define fields. 1919
MembrosMembers Membros de tipo em geralType members in general Campos e métodos estáticos globais não são compatíveis com CLS.Global static fields and methods are not CLS-compliant. 3636
MembrosMembers -- O valor de um estático literal é especificado por meio do uso de metadados de inicialização do campo.The value of a literal static is specified through the use of field initialization metadata. Um literal compatível com CLS deve ter um valor especificado em metadados de inicialização de campo que sejam exatamente do mesmo tipo que o literal (ou do tipo subjacente, se esse literal for um 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
MembrosMembers Membros de tipo em geralType members in general A restrição vararg não faz parte da CLS e a única convenção de chamada com suporte pela CLS é a convenção de chamada gerenciada padrão.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
Convenções de nomenclaturaNaming conventions Convenções de nomenclaturaNaming conventions Os assemblies deverão seguir o Anexo 7 do Relatório Técnico 15 do Padrão Unicode 3.0 que controla o conjunto de caracteres que podem iniciar e ser incluídos em identificadores, disponíveis online em 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. Os identificadores deverão estar no formato canônico definido pelo Formulário C de Normalização de Unicode. Para fins de CLS, dois identificadores serão iguais se os mapeamentos em minúsculas (conforme especificado pelos mapeamentos em minúsculas um para um, insensíveis a localidade Unicode) forem os mesmos.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. Ou seja, para dois identificadores serem considerados diferentes na CLS, eles deverão ser diferentes além de apenas maiúsculas e minúsculas.That is, for two identifiers to be considered different under the CLS they shall differ in more than simply their case. No entanto, para substituir uma definição herdada, a CLI exige que a codificação precisa da declaração original seja usada.However, in order to override an inherited definition the CLI requires the precise encoding of the original declaration be used. 44
SobrecargaOverloading Convenções de nomenclaturaNaming conventions Todos os nomes introduzidos em um escopo compatível com CLS deverão ser independentes e distintos do tipo, exceto quando os nomes forem idênticos e resolvidos por meio da sobrecarga.All names introduced in a CLS-compliant scope shall be distinct independent of kind, except where the names are identical and resolved via overloading. Ou seja, embora o CTS permita que um único tipo use o mesmo nome para um método e um campo, a CLS não permite.That is, while the CTSallows a single type to use the same name for a method and a field, the CLS does not. 55
SobrecargaOverloading Convenções de nomenclaturaNaming conventions Campos e tipos aninhados deverão ser diferenciados apenas por comparação de identificador, mesmo que o CTS permita que assinaturas diferentes sejam distinguidas.Fields and nested types shall be distinct by identifier comparison alone, even though the CTS allows distinct signatures to be distinguished. Métodos, propriedades e eventos com o mesmo nome (por comparação de identificador) deverão ser diferentes além apenas do tipo de retorno, exceto conforme especificado na Regra 39 da CLS.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
SobrecargaOverloading SobrecargasOverloads Somente propriedades e métodos podem ser sobrecarregados.Only properties and methods can be overloaded. 3737
SobrecargaOverloading SobrecargasOverloads As propriedades e os métodos só podem ser sobrecarregados com base no número e nos tipos de seus parâmetros, exceto os operadores de conversão chamados op_Implicit e op_Explicit, que também podem ser sobrecarregados com base no tipo de retorno.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
SobrecargaOverloading -- Se dois ou mais métodos em conformidade com CLS declarados em um tipo tiverem o mesmo nome e, para um conjunto específico de instanciações de tipo, tiverem os mesmos tipos de parâmetro e retorno, esses métodos deverão ser semanticamente equivalentes nessas instanciações de 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
TiposTypes Tipo e assinaturas de membro de tipoType and type member signatures System.Object é compatível com CLS.System.Object is CLS-compliant. Qualquer outra classe compatível com CLS deverá herdar de uma classe compatível com CLS.Any other CLS-compliant class shall inherit from a CLS-compliant class. 2323
PropriedadesProperties PropriedadesProperties Os métodos que implementam os métodos getter e setter de uma propriedade deverão ser marcados como SpecialName nos metadados.The methods that implement the getter and setter methods of a property shall be marked SpecialName in the metadata. 2424
PropriedadesProperties PropriedadesProperties Os acessadores de uma propriedade deverão ser todos estáticos, virtuais ou de instância.A property’s accessors shall all be static, all be virtual, or all be instance. 2626
PropriedadesProperties PropriedadesProperties O tipo de uma propriedade deverá ser o tipo de retorno do getter e o tipo do último argumento do setter.The type of a property shall be the return type of the getter and the type of the last argument of the setter. Os tipos dos parâmetros da propriedade deverão ser os tipos dos parâmetros do getter e os tipos de todos os parâmetros, menos o parâmetro final do setter.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. Todos esses tipos deverão ser compatíveis com CLS e não deverão ser ponteiros gerenciados (por exemplo, não deverão ser passados por referência).All of these types shall be CLS-compliant, and shall not be managed pointers (i.e., shall not be passed by reference). 2727
PropriedadesProperties PropriedadesProperties As propriedades deverão seguir um padrão de nomenclatura específico.Properties shall adhere to a specific naming pattern. O atributo SpecialName mencionado na regra 24 da CLS deverá ser ignorado em comparações de nome apropriadas e respeitar as regras do identificador.The SpecialName attribute referred to in CLS rule 24 shall be ignored in appropriate name comparisons and shall adhere to identifier rules. Uma propriedade deverá ter um método getter, um método setter ou ambos.A property shall have a getter method, a setter method, or both. 2828
Conversão de tiposType conversion Conversão de tiposType conversion Se op_Implicit ou op_Explicit for fornecido, um meio alternativo de fornecimento da coerção deverá ser fornecido.If either op_Implicit or op_Explicit is provided, an alternate means of providing the coercion shall be provided. 3939
TiposTypes Tipo e assinaturas de membro de tipoType and type member signatures Tipos de valor demarcado não são compatíveis com CLS.Boxed value types are not CLS-compliant. 33
TiposTypes Tipo e assinaturas de membro de tipoType and type member signatures Todos os tipos exibidos em uma assinatura deverão ser compatíveis com CLS.All types appearing in a signature shall be CLS-compliant. Todos os tipos que compõem um tipo genérico instanciado deverão ser compatíveis com CLS.All types composing an instantiated generic type shall be CLS-compliant. 1111
TiposTypes Tipo e assinaturas de membro de tipoType and type member signatures Referências com tipo não são compatíveis com CLS.Typed references are not CLS-compliant. 1414
TiposTypes Tipo e assinaturas de membro de tipoType and type member signatures Tipos de ponteiro não gerenciados não são compatíveis com CLS.Unmanaged pointer types are not CLS-compliant. 1717
TiposTypes Tipo e assinaturas de membro de tipoType and type member signatures Classes compatíveis com CLS, tipos de valor e interfaces não deverão exigir a implementação de membros incompatíveis com CLS.CLS-compliant classes, value types, and interfaces shall not require the implementation of non-CLS-compliant members. 2020

Tipos e assinaturas de membro de tipoTypes and type member signatures

O tipo System.Object é compatível com CLS e é o tipo base de todos os tipos de objeto no sistema de tipos do .NET Framework.The System.Object type is CLS-compliant and is the base type of all object types in the .NET Framework type system. A herança no .NET Framework é implícita (por exemplo, a classe String herda implicitamente da classe Object) ou explícita (por exemplo, a classe CultureNotFoundException herda explicitamente da classe ArgumentException, que herda explicitamente da classe SystemException, que herda explicitamente da 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). Para que um tipo derivado seja compatível com CLS, seu tipo base também deverá ser compatível com CLS.For a derived type to be CLS compliant, its base type must also be CLS-compliant.

O exemplo a seguir mostra um tipo derivado cujo tipo de base não é compatível com CLS.The following example shows a derived type whose base type is not CLS-compliant. Ele define uma classe Counter base que usa um inteiro de 32 bits sem sinal como um contador.It defines a base Counter class that uses an unsigned 32-bit integer as a counter. Como a classe fornece funcionalidade de contador encapsulando um inteiro sem sinal, a classe é marcada como não compatível com CLS.Because the class provides counter functionality by wrapping an unsigned integer, the class is marked as non-CLS-compliant. Assim, uma classe derivada, NonZeroCounter, também não é compatível com 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
'                 ~~~~~~~~~~~~~~

Todos os tipos exibidos em assinaturas de membro, incluindo um tipo de retorno de método ou um tipo de propriedade, devem ser compatíveis com CLS.All types that appear in member signatures, including a method's return type or a property type, must be CLS-compliant. Além disso, para tipos genéricos:In addition, for generic types:

  • Todos os tipos que compõe um tipo genérico instanciado devem ser compatíveis com CLS.All types that compose an instantiated generic type must be CLS-compliant.

  • Todos os tipos usados como restrições em parâmetros genéricos devem ser compatíveis com CLS.All types used as constraints on generic parameters must be CLS-compliant.

O Common Type System do .NET Framework inclui vários tipos internos que têm suporte direto do Common Language Runtime e são codificados especialmente nos metadados de um 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. Desses tipos intrínsecos, os tipos listados na tabela a seguir são compatíveis com CLS.Of these intrinsic types, the types listed in the following table are CLS-compliant.

Tipo compatível com CLSCLS-compliant type DESCRIÇÃODescription
Byte Inteiro sem sinal de 8 bits8-bit unsigned integer
Int16 Inteiro com sinal de 16 bits16-bit signed integer
Int32 Inteiro com sinal de 32 bits32-bit signed integer
Int64 Inteiro com sinal de 64 bits64-bit signed integer
Single Valor do ponto flutuante de precisão simplesSingle-precision floating-point value
Double Valor do ponto flutuante de precisão duplaDouble-precision floating-point value
Boolean Tipo de valor true ou falsetrue or false value type
Char unidade de código codificado UTF-16UTF-16 encoded code unit
Decimal Número decimal de ponto não flutuanteNon-floating-point decimal number
IntPtr Ponteiro ou identificador de um tamanho definido por plataformaPointer or handle of a platform-defined size
String Coleção de zero, um ou mais objetos CharCollection of zero, one, or more Char objects

Os tipos intrínsecos listados na tabela a seguir não são compatíveis com CLS.The intrinsic types listed in the following table are not CLS-Compliant.

Tipo não compatívelNon-compliant type DESCRIÇÃODescription Alternativa compatível com CLSCLS-compliant alternative
SByte Tipo de dados inteiro com sinal de 8 bits8-bit signed integer data type Int16
TypedReference Ponteiro para um objeto e seu tipo de tempo de execuçãoPointer to an object and its runtime type NenhumNone
UInt16 Inteiro sem sinal de 16 bits16-bit unsigned integer Int32
UInt32 Inteiro sem sinal de 32 bits32-bit unsigned integer Int64
UInt64 Inteiro sem sinal de 64 bits64-bit unsigned integer Int64 (pode estourar), BigInteger ou DoubleInt64 (may overflow), BigInteger, or Double
UIntPtr Ponteiro ou identificador sem sinalUnsigned pointer or handle IntPtr

A biblioteca de classes .NET Framework ou qualquer outra biblioteca de classes pode incluir outros tipos que não sejam compatíveis com CLS; por exemplo:The .NET Framework Class Library or any other class library may include other types that aren't CLS-compliant; for example:

  • Tipos de valor demarcado.Boxed value types. O exemplo do C# a seguir cria uma classe que tem uma propriedade pública do tipo int* chamada Value.The following C# example creates a class that has a public property of type int* named Value. Como um int* é um tipo de valor demarcado, o compilador o sinaliza como incompatível com CLS.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
    
  • Referências de tipo, que são constructos especiais que contêm referência a um objeto e referência a um tipo.Typed references, which are special constructs that contain a reference to an object and a reference to a type. As referências tipadas são representadas no .NET Framework pela classe TypedReference.Typed references are represented in the .NET Framework by the TypedReference class.

Se um tipo não for compatível com CLS, você deverá aplicar o atributo CLSCompliantAttribute com um valor isCompliant de false a ele.If a type is not CLS-compliant, you should apply the CLSCompliantAttribute attribute with an isCompliant value of false to it. Para obter mais informações, consulte a seção O atributo CLSCompliantAttribute.For more information, see The CLSCompliantAttribute attribute section.

O exemplo a seguir ilustra o problema de conformidade com CLS em uma assinatura do método e em uma instanciação de tipo genérico.The following example illustrates the problem of CLS compliance in a method signature and in generic type instantiation. Ele define uma classe InvoiceItem com uma propriedade do tipo UInt32, uma propriedade do tipo Nullable(Of UInt32) e um construtor com parâmetros de 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). Você recebe quatro avisos do compilador ao tentar de compilar esse exemplo.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
'                       ~~~~~~~~~

Para eliminar os avisos do compilador, substitua os tipos não compatíveis com CLS na interface pública InvoiceItem por tipos compatíveis: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

Além dos tipos específicos listados, algumas categorias de tipos não são compatíveis com CLS.In addition to the specific types listed, some categories of types are not CLS compliant. Entre eles estão tipos de ponteiro não gerenciados e tipos de ponteiro de função.These include unmanaged pointer types and function pointer types. O exemplo a seguir gera um aviso do compilador porque ele usa um ponteiro para um inteiro a fim de criar uma matriz de inteiros.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

Para classes abstratas compatíveis com CLS (ou seja, classes marcadas como abstract no C# ou como MustInherit no Visual Basic), todos os membros da classe também devem ser compatíveis com 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.

Convenções de nomenclaturaNaming conventions

Como algumas linguagens de programação não diferenciam maiúsculas de minúsculas, os identificadores (como nomes de namespaces, tipos e membros) devem se diferenciar além de maiúsculas e minúsculas.Because some programming languages are case-insensitive, identifiers (such as the names of namespaces, types, and members) must differ by more than case. Dois identificadores serão considerados equivalentes se seus mapeamentos em minúsculas forem os mesmos.Two identifiers are considered equivalent if their lowercase mappings are the same. O exemplo do C# a seguir define duas classes públicas, Person e person.The following C# example defines two public classes, Person and person. Como elas são diferentes apenas em maiúsculas e minúsculas, o compilador do C# as sinaliza como não compatíveis com 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)

Identificadores de linguagem de programação, como nomes de namespaces, tipos e membros, devem estar de acordo com o Padrão Unicode 3.0, Relatório Técnico 15, Anexo 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. Isso significa que:This means that:

  • O primeiro caractere de um identificador pode ser qualquer letra maiúscula Unicode, letra minúscula, letra maiúscula do título, letra modificadora, outra letra ou o número da letra.The first character of an identifier can be any Unicode uppercase letter, lowercase letter, title case letter, modifier letter, other letter, or letter number. Para obter informações sobre categorias de caracteres Unicode, consulte a enumeração System.Globalization.UnicodeCategory.For information on Unicode character categories, see the System.Globalization.UnicodeCategory enumeration.

  • Os caracteres subsequentes podem ser de qualquer uma das categorias, como o primeiro caractere e também podem incluir marcas sem espaçamento, marcas que combinam espaçamento, números decimais, pontuações de conector e códigos de formatação.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.

Antes de comparar identificadores, você deve filtrar códigos de formatação e converter os identificadores em Formulário C de Normalização de Unicode, porque um caractere único pode ser representado por várias unidades de código codificadas em 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. As sequências de caracteres que produzem as mesmas unidades de código no Formulário C de Normalização de Unicode não são compatíveis com CLS.Character sequences that produce the same code units in Unicode Normalization Form C are not CLS-compliant. O exemplo a seguir define uma propriedade chamada , que consiste no caractere SÍMBOLO DE ANGSTROM (U+212B) e uma segunda propriedade chamada Å, que consiste no caractere LETRA LATINA MAIÚSCULA A COM ANEL SUPERIOR (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). Os compiladores do C# e do Visual Basic sinalizam o código-fonte como incompatível com 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
'                       ~

Os nomes de membro em um escopo específico (como os namespaces em um assembly, os tipos em um namespace ou os membros em um tipo) devem ser exclusivos, exceto os nomes resolvidos por meio de sobrecarga.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. Esse requisito é mais rígido do que o do Common Type System, que permite que vários membros em um escopo tenham nomes idênticos desde que sejam tipos diferentes de membros (por exemplo, um é um método e outro é um 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). Em particular, para membros de tipo:In particular, for type members:

  • Campos e tipos aninhados são diferenciados apenas por nome.Fields and nested types are distinguished by name alone.

  • Métodos, propriedades e eventos que tenham o mesmo nome devem ser diferentes além apenas do tipo de retorno.Methods, properties, and events that have the same name must differ by more than just return type.

O exemplo a seguir ilustra o requisito de que nomes de membros devem ser exclusivos dentro de seu escopo.The following example illustrates the requirement that member names must be unique within their scope. Ele define uma classe chamada Converter que inclui quatro membros chamados Conversion.It defines a class named Converter that includes four members named Conversion. Três são métodos e um é uma propriedade.Three are methods, and one is a property. O método que inclui um parâmetro Int64 tem um nome exclusivo, mas os dois métodos com um parâmetro Int32 não têm, porque o valor retornado não é considerado parte da assinatura de um 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. A propriedade Conversion também viola esse requisito porque as propriedades não podem ter o mesmo nome dos métodos sobrecarregados.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
'                                ~~~~~~~~~~

Linguagens individuais incluem palavras-chave exclusivas, portanto, linguagens que apontam para o Common Language Runtime também devem oferecer algum mecanismo para fazer referência a identificadores (como nomes de tipo) que coincidam com palavras-chave.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. Por exemplo, case é uma palavra-chave no C# e no Visual Basic.For example, case is a keyword in both C# and Visual Basic. No entanto, o exemplo do Visual Basic a seguir pode remover a ambiguidade de uma classe chamada case da palavra-chave case, usando chaves de abertura e fechamento.However, the following Visual Basic example is able to disambiguate a class named case from the case keyword by using opening and closing braces. Caso contrário, o exemplo produziria a mensagem de erro "A palavra-chave não é válida como um identificador", e não seria compilado.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

O exemplo do C# a seguir pode criar uma instância da classe case usando o símbolo @ para remover a ambiguidade do identificador da palavras-chave da linguagem.The following C# example is able to instantiate the case class by using the @ symbol to disambiguate the identifier from the language keyword. Sem ele, o compilador do C# exibiria duas mensagens de erro, "Tipo esperado" e "'Maiúsculas e minúsculas' do termo de expressão inválido".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);
   }
}

Conversão de tiposType conversion

A Common Language Specification define dois operadores de conversão:The Common Language Specification defines two conversion operators:

  • op_Implicit, que é usado para conversões de ampliação que não resultam em perda de dados ou precisão.op_Implicit, which is used for widening conversions that do not result in loss of data or precision. Por exemplo, a estrutura Decimal inclui um operador op_Implicit sobrecarregado para converter valores de tipos integrais e valores Char em valores 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, que é usado para conversões de redução que possam resultar em perda de magnitude (um valor é convertido em um valor com um intervalo menor) ou precisão.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. Por exemplo, a estrutura Decimal inclui um operador op_Explicit sobrecarregado para converter Double e valores Single em Decimal e para converter valores Decimal em valores inteiros, o 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.

No entanto, nem todas as linguagens dão suporte à sobrecarga de operador ou à definição de operadores personalizados.However, not all languages support operator overloading or the definition of custom operators. Se optar por implementar esses operadores de conversão, você também deverá fornecer uma maneira alternativa para realizar a conversão.If you choose to implement these conversion operators, you should also provide an alternate way to perform the conversion. Recomendamos que você forneça os métodos FromXxx e ToXxx.We recommend that you provide FromXxx and ToXxx methods.

O exemplo a seguir define conversões explícitas e implícitas compatíveis com CLS.The following example defines CLS-compliant implicit and explicit conversions. Ele cria uma classe UDouble que representa um número de ponto flutuante de precisão dupla com sinal.It creates a UDouble class that represents an signed double-precision, floating-point number. Ele fornece conversões implícitas de UDouble em Double e conversões explícitas de UDouble em Single, de Double em UDouble e de Single em 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. Ele também define um método ToDouble como uma alternativa ao operador de conversão implícita e os métodos ToSingle, FromDouble e FromSingle como alternativas aos operadores de conversão explícita.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

MatrizesArrays

As matrizes compatíveis com CLS estão em conformidade com as seguintes regras:CLS-compliant arrays conform to the following rules:

  • Todas as dimensões de uma matriz devem ter um limite inferior igual a zero.All dimensions of an array must have a lower bound of zero. O exemplo a seguir cria uma matriz não compatível com CLS com um limite inferior de um.The following example creates a non-CLS-compliant array with a lower bound of one. Independentemente da presença do atributo CLSCompliantAttribute, o compilador não detecta se a matriz retornada pelo método Numbers.GetTenPrimes não é compatível com 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
    
  • Todos os elementos de matriz devem consistir em tipos compatíveis com CLS.All array elements must consist of CLS-compliant types. O exemplo a seguir define dois métodos que retornam matrizes não compatíveis com CLS.The following example defines two methods that return non-CLS-compliant arrays. O primeiro retorna uma matriz de valores UInt32.The first returns an array of UInt32 values. O segundo retorna uma matriz Object que inclui valores Int32 e UInt32.The second returns an Object array that includes Int32 and UInt32 values. Embora o compilador identifique a primeira matriz como não compatível devido ao seu tipo UInt32, ele não reconhece que a segunda matriz inclui elementos não compatíveis com 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()
    '                              ~~~~~~~~~~~~
    
  • A resolução de sobrecarga para métodos que tenham parâmetros de matriz se baseia no fato de que são matrizes e em seu tipo de elemento.Overload resolution for methods that have array parameters is based on the fact that they are arrays and on their element type. Por esse motivo, a seguinte definição de um método GetSquares sobrecarregado é compatível com 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
    

InterfacesInterfaces

Interfaces compatíveis com CLS podem definir propriedades, eventos e métodos virtuais (métodos sem implementação).CLS-compliant interfaces can define properties, events, and virtual methods (methods with no implementation). Uma interface compatível com CLS não pode ter nenhum dos seguintes itens:A CLS-compliant interface cannot have any of the following:

  • Métodos estáticos ou campos estáticos.Static methods or static fields. Os compiladores do C# e do Visual Basic gerarão erros de compilador se você definir um membro estático em uma interface.Both the C# and Visual Basic compilers generate compiler errors if you define a static member in an interface.

  • Campos.Fields. Os compiladores do C# e do Visual Basic gerarão erros de compilador se você definir um campo em uma interface.Both the C# and Visual Basic compilers generate compiler errors if you define a field in an interface.

  • Métodos que não são compatíveis com CLS.Methods that are not CLS-compliant. Por exemplo, a definição a seguir da interface inclui um método, INumber.GetUnsigned, que está marcado como não compatível com CLS.For example, the following interface definition includes a method, INumber.GetUnsigned, that is marked as non-CLS-compliant. Este exemplo gera um aviso do compilador.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
    '                                      ~~~~~~~~~~~
    

    Devido a essa regra, os tipos compatíveis com CLS não são necessários para implementar membros não compatíveis com CLS.Because of this rule, CLS-compliant types are not required to implement non-CLS-compliant members. Se uma estrutura compatível com CLS expuser uma classe que implementa uma interface não compatível com CLS, ela também deverá fornecer implementações concretas de todos os membros não compatíveis com 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.

Compiladores de linguagem compatíveis com CLS também devem permitir que uma classe forneça implementações separadas dos membros com o mesmo nome e a assinatura em várias interfaces.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. O C# e o Visual Basic dão suporte a implementações explícitas de interface para fornecer implementações diferentes de métodos com nomes idênticos.Both C# and Visual Basic support explicit interface implementations to provide different implementations of identically named methods. O Visual Basic também dá suporte à palavra-chave Implements, que permite que você designe explicitamente qual interface e membro um determinado membro implementa.Visual Basic also supports the Implements keyword, which enables you to explicitly designate which interface and member a particular member implements. O exemplo a seguir ilustra esse cenário, definindo uma classe Temperature que implementa as interfaces ICelsius e IFahrenheit como implementações explícitas de interface.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

EnumeraçõesEnumerations

Enumerações compatíveis com CLS devem seguir estas regras:CLS-compliant enumerations must follow these rules:

  • O tipo subjacente da enumeração deve ser um inteiro intrínseco compatível com CLS (Byte, Int16, Int32 ou Int64).The underlying type of the enumeration must be an intrinsic CLS-compliant integer (Byte, Int16, Int32, or Int64). Por exemplo, o código a seguir tenta definir uma enumeração cujo tipo subjacente é UInt32 e gera um aviso do compilador.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
    '                ~~~~
    
  • Um tipo de enumeração deve ter um campo de instância única chamado Value__ que foi marcado com o atributo FieldAttributes.RTSpecialName.An enumeration type must have a single instance field named Value__ that is marked with the FieldAttributes.RTSpecialName attribute. Isso permite que você referencie o valor do campo implicitamente.This enables you to reference the field value implicitly.

  • Uma enumeração inclui campos estáticos literais, cujos tipos correspondem ao tipo da própria enumeração.An enumeration includes literal static fields whose types match the type of the enumeration itself. Por exemplo, se você definir uma enumeração State com valores de State.On e State.Off, State.On e State.Off serão campos literais estáticos cujo tipo será 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.

  • Há dois tipos de enumeração:There are two kinds of enumerations:

    • Uma enumeração que representa um conjunto de valores mutuamente excludentes, valores inteiros nomeados.An enumeration that represents a set of mutually exclusive, named integer values. Esse tipo de enumeração é indicado pela ausência do atributo personalizado System.FlagsAttribute.This type of enumeration is indicated by the absence of the System.FlagsAttribute custom attribute.

    • Uma enumeração que representa um conjunto de sinalizadores de bit que podem ser combinados para produzir um valor sem nome.An enumeration that represents a set of bit flags that can combine to generate an unnamed value. Esse tipo de enumeração é indicado pela presença do atributo personalizado System.FlagsAttribute.This type of enumeration is indicated by the presence of the System.FlagsAttribute custom attribute.

    Para obter mais informações, consulte a documentação da estrutura Enum.For more information, see the documentation for the Enum structure.

  • O valor de uma enumeração não está limitado ao intervalo de seus valores especificados.The value of an enumeration is not limited to the range of its specified values. Em outras palavras, o intervalo de valores em uma enumeração é o intervalo de seu valor subjacente.In other words, the range of values in an enumeration is the range of its underlying value. Você pode usar o método Enum.IsDefined para determinar se um valor especificado é membro de uma enumeração.You can use the Enum.IsDefined method to determine whether a specified value is a member of an enumeration.

Membros de tipo em geralType members in general

O Common Language Specification requer que todos os campos e métodos sejam acessados como membros de uma classe específica.The Common Language Specification requires all fields and methods to be accessed as members of a particular class. Portanto, campos e métodos estáticos globais (ou seja, campos ou métodos estáticos que são definidos independentemente de um tipo) não são compatíveis com 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 você tentar incluir um campo ou um método global em seu código fonte, os compiladores do C# e do Visual Basic gerarão um erro de compilador.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.

A Common Language Specification dá suporte somente à convenção de chamada gerenciada padrão.The Common Language Specification supports only the standard managed calling convention. Ela não dá suporte a convenções e métodos de chamada não gerenciados com listas de argumentos de variável marcadas com a palavra-chave varargs.It doesn't support unmanaged calling conventions and methods with variable argument lists marked with the varargs keyword. Para as listas de argumentos variáveis que são compatíveis com a convenção de chamada gerenciada padrão, use o atributo ParamArrayAttribute ou a implementação da linguagem individual, como a palavra-chave params no C# e a palavra-chave ParamArray no 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.

Acessibilidade de membroMember accessibility

A substituição de um membro herdado não pode alterar a acessibilidade desse membro.Overriding an inherited member cannot change the accessibility of that member. Por exemplo, um método público em uma classe base não pode ser substituído por um método privado em uma classe derivada.For example, a public method in a base class cannot be overridden by a private method in a derived class. Há uma exceção: um membro protected internal (em C#) ou Protected Friend (em Visual Basic) em um assembly que é substituído por um tipo em um assembly diferente.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. Nesse caso, a acessibilidade da substituição é Protected.In that case, the accessibility of the override is Protected.

O exemplo a seguir ilustra o erro que é gerado quando o atributo CLSCompliantAttribute é definido como true e Human, que é uma classe derivada de Animal tenta alterar a acessibilidade da propriedade Species de chave pública para privada.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. O exemplo será compilado com êxito se sua acessibilidade for alterada para pública.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

Os tipos na assinatura de um membro deverão ser acessíveis sempre que o membro for acessível.Types in the signature of a member must be accessible whenever that member is accessible. Por exemplo, isso significa que um membro público não pode incluir um parâmetro cujo tipo seja privado, protegido ou interno.For example, this means that a public member cannot include a parameter whose type is private, protected, or internal. O exemplo a seguir ilustra o erro do compilador que resulta quando um construtor de classe StringWrapper expõe um valor de enumeração StringOperationType interno que determina como um valor de cadeia de caracteres deve ser encapsulado.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)
'                              ~~~~~~~~~~~~~~~~~~~

Tipos e membros genéricosGeneric types and members

Tipos aninhados sempre têm pelo menos o mesmo número de parâmetros genéricos do tipo delimitador.Nested types always have at least as many generic parameters as their enclosing type. Eles correspondem por posição aos parâmetros genéricos no tipo delimitador.These correspond by position to the generic parameters in the enclosing type. O tipo genérico também pode incluir novos parâmetros genéricos.The generic type can also include new generic parameters.

A relação entre os parâmetros de tipo genérico de um tipo de contenção e seus tipos aninhados pode ser ocultada pela sintaxe de linguagens individuais.The relationship between the generic type parameters of a containing type and its nested types may be hidden by the syntax of individual languages. No exemplo a seguir, um tipo genérico Outer<T> contém duas classes aninhadas, Inner1A e Inner1B<U>.In the following example, a generic type Outer<T> contains two nested classes, Inner1A and Inner1B<U>. As chamadas para o método ToString, que cada classe herda de Object.ToString, mostra que cada classe aninhada inclui parâmetros de tipo de sua classe de contenção.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]

Os nomes de tipo genérico são codificados no formato nome`n, em que nome é o nome do tipo, ` é um literal de caractere e n é o número de parâmetros declarados no tipo ou, para tipos genéricos aninhados, o número de parâmetros de tipo recém-introduzidos.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. Essa codificação de nomes de tipo genéricos é principalmente de interesse de desenvolvedores que usam a reflexão para acessar tipos genéricos compatíveis com CLS em uma biblioteca.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 as restrições forem aplicadas a um tipo genérico, qualquer tipo usado como restrição também deverá ser compatível com CLS.If constraints are applied to a generic type, any types used as constraints must also be CLS-compliant. O exemplo a seguir define uma classe chamada BaseClass que não é compatível com CLS e uma classe genérica chamada BaseCollection cujo parâmetro de tipo deve derivar de 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. Mas como BaseClass não é compatível com CLS, o compilador emite um aviso.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 um tipo genérico for derivado de um tipo de base genérico, ele deverá redeclarar todas as restrições, para assegurar que as restrições no tipo de base também sejam atendidas.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. O exemplo a seguir define um Number<T> que pode representar qualquer tipo numérico.The following example defines a Number<T> that can represent any numeric type. Ele também define uma classe FloatingPoint<T> que representa um valor de ponto flutuante.It also defines a FloatingPoint<T> class that represents a floating point value. No entanto, o código-fonte falha na compilação porque não aplica a restrição em Number<T> (esse T deve ser um tipo de valor) 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)
'                                                          ~

O exemplo será compilado com êxito se a restrição for adicionada à 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           

A Common Language Specification impõe um modelo por instanciação conservador para tipos aninhados e membros protegidos.The Common Language Specification imposes a conservative per-instantiation model for nested types and protected members. Tipos genéricos abertos não podem expor campos ou membros com assinaturas que contenham uma instanciação específica de um tipo genérico aninhado, protegido.Open generic types cannot expose fields or members with signatures that contain a specific instantiation of a nested, protected generic type. Tipos não genéricos que estendam uma instanciação específica de uma interface ou classe base genérica não podem expor campos ou membros com assinaturas que contenham uma instanciação diferente de um tipo genérico aninhado e protegido.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.

O exemplo a seguir define um tipo genérico, C1<T> (ou C1(Of T) no Visual Basic) e uma classe protegida, C1<T>.N (ou C1(Of T).N no 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). C1<T> possui dois métodos, M1 e M2.C1<T> has two methods, M1 and M2. No entanto, M1 é sem conformidade com CLS porque tenta retornar um objeto C1<int>.N (ou C1(Of Integer).N) de C1<T> (ou 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)). Uma segunda classe, C2, é derivada de C1<long> (ou de C1(Of Long)).A second class, C2, is derived from C1<long> (or C1(Of Long)). Tem dois métodos, M3 e M4.It has two methods, M3 and M4. No entanto, M3 não é compatível com CLS porque tenta retornar um objeto C1<int>.N (ou C1(Of Integer).N) de uma subclasse de 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>. Os compiladores de linguagens podem ser ainda mais restritivos.Note that language compilers can be even more restrictive. Neste exemplo, o Visual Basic exibe um erro ao tentar compilar 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)  
'                             ~~~~~~~~~~~~~

ConstrutoresConstructors

Os construtores em classes compatíveis com CLS e em estruturas devem seguir estas regras:Constructors in CLS-compliant classes and structures must follow these rules:

  • Um construtor de uma classe derivada deve chamar o construtor de instância de sua classe base antes de acessar quaisquer dados de instância herdados.A constructor of a derived class must call the instance constructor of its base class before it accesses inherited instance data. Esse requisito deve-se ao fato de que construtores de classe base não são herdados por suas classes derivadas.This requirement is due to the fact that base class constructors are not inherited by their derived classes. Essa regra não se aplica a estruturas que não dão suporte a herança direta.This rule does not apply to structures, which do not support direct inheritance.

    Normalmente, os compiladores aplicam essa regra independentemente da conformidade com CLS, conforme mostrado no exemplo a seguir.Typically, compilers enforce this rule independently of CLS compliance, as the following example shows. Ele cria uma classe Doctor que é derivada de uma classe Person, mas a classe Doctor falha ao chamar o construtor de classe Person para inicializar campos herdados da instância.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()
    '                  ~~~
    
  • Um construtor de objeto não pode ser chamado, exceto para criar um objeto.An object constructor cannot be called except to create an object. Além disso, um objeto não pode ser inicializado duas vezes.In addition, an object cannot be initialized twice. Por exemplo, isso significa que Object.MemberwiseClone e métodos de desserialização como BinaryFormatter.Deserialize não devem chamar construtores.For example, this means that Object.MemberwiseClone and deserialization methods such as BinaryFormatter.Deserialize must not call constructors.

PropriedadesProperties

As propriedades em tipos compatíveis com CLS devem seguir estas regras:Properties in CLS-compliant types must follow these rules:

  • Uma propriedade deve ter um setter, um getter ou ambos.A property must have a setter, a getter, or both. Em um assembly, eles são implementados como métodos especiais, o que significa que aparecerão como métodos separados (o getter é chamado de get_propertyname e o setter é set_propertyname) marcado como SpecialName nos metadados do 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. Os compiladores do C# e do Visual Basic aplicam automaticamente essa regra, sem a necessidade de aplicar o atributo CLSCompliantAttribute.The C# and Visual Basic compilers enforce this rule automatically without the need to apply the CLSCompliantAttribute attribute.

  • Um tipo de propriedade é o tipo de retorno do getter da propriedade e o último argumento do setter.A property's type is the return type of the property getter and the last argument of the setter. Esses tipos devem ser compatíveis com CLS e os argumentos não podem ser atribuídos à propriedade por referência (ou seja, não podem ser ponteiros gerenciados).These types must be CLS compliant, and arguments cannot be assigned to the property by reference (that is, they cannot be managed pointers).

  • Se uma propriedade tiver um getter e um setter, ambos deverão ser virtuais, estáticos ou instâncias.If a property has both a getter and a setter, they must both be virtual, both static, or both instance. Os compiladores do C# e do Visual Basic aplicam automaticamente essa regra por meio de sua sintaxe de definição da propriedade.The C# and Visual Basic compilers automatically enforce this rule through their property definition syntax.

EventosEvents

Um evento é definido por seu nome e tipo.An event is defined by its name and its type. O tipo de evento é um delegado que é usado para indicar o evento.The event type is a delegate that is used to indicate the event. Por exemplo, o evento AppDomain.AssemblyResolve é do tipo ResolveEventHandler.For example, the AppDomain.AssemblyResolve event is of type ResolveEventHandler. Além do evento em si, três métodos com nomes com base no nome do evento fornecem a implementação do evento e estão marcados como SpecialName nos metadados do 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:

  • Um método para adicionar um manipulador de eventos, chamado add_EventName.A method for adding an event handler, named add_EventName. Por exemplo, o método de assinatura do evento para o evento AppDomain.AssemblyResolve é chamado add_AssemblyResolve.For example, the event subscription method for the AppDomain.AssemblyResolve event is named add_AssemblyResolve.

  • Um método para remover um manipulador de eventos, chamado remove_EventName.A method for removing an event handler, named remove_EventName. Por exemplo, o método de remoção para o evento AppDomain.AssemblyResolve é chamado remove_AssemblyResolve.For example, the removal method for the AppDomain.AssemblyResolve event is named remove_AssemblyResolve.

  • Um método para indicar que o evento ocorreu, chamado raise_EventName.A method for indicating that the event has occurred, named raise_EventName.

Observação

A maioria das regras da Common Language Specification em relação a eventos é implementada por compiladores de linguagem e é transparente para desenvolvedores de componente.Most of the Common Language Specification's rules regarding events are implemented by language compilers and are transparent to component developers.

Os métodos para adicionar, remover e acionar o evento devem ter a mesma acessibilidade.The methods for adding, removing, and raising the event must have the same accessibility. Eles também devem ser todos estáticos, instâncias ou virtuais.They must also all be static, instance, or virtual. Os métodos para adicionar e remover um evento têm um parâmetro cujo tipo é o tipo de delegado do evento.The methods for adding and removing an event have one parameter whose type is the event delegate type. Os métodos para adicionar e remover devem estar ambos presentes ou ausentes.The add and remove methods must both be present or both be absent.

O exemplo a seguir define uma classe compatível com CLS chamada Temperature que acionará um evento TemperatureChanged se a mudança de temperatura entre as duas leituras for igual ou exceder o valor de limite.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. A classe Temperature define explicitamente um método raise_TemperatureChanged para executar seletivamente os manipuladores de eventos.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

SobrecargasOverloads

A Common Language Specification impõe os seguintes requisitos em membros sobrecarregados:The Common Language Specification imposes the following requirements on overloaded members:

  • Os membros podem ser sobrecarregados com base no número de parâmetros e no tipo de qualquer parâmetro.Members can be overloaded based on the number of parameters and the type of any parameter. A convenção de chamada, o tipo de retorno, os modificadores personalizados aplicados ao método ou seus parâmetros e se os parâmetros são passados por valor ou por referência não são considerados na diferenciação entre sobrecargas.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. Para obter um exemplo, consulte o código para o requisito de que os nomes devem ser exclusivos em um escopo na seção Convenções de nomenclatura.For an example, see the code for the requirement that names must be unique within a scope in the Naming conventions section.

  • Somente propriedades e métodos podem ser sobrecarregados.Only properties and methods can be overloaded. Campos e eventos não podem ser sobrecarregados.Fields and events cannot be overloaded.

  • Métodos genéricos podem ser sobrecarregados com base no número de seus parâmetros genéricos.Generic methods can be overloaded based on the number of their generic parameters.

Observação

Os operadores op_Explicit e op_Implicit são exceções à regra de que o valor retornado não é considerado parte de uma assinatura de método para resolução de sobrecarga.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. Esses dois operadores podem ser sobrecarregados com base nos parâmetros e valor retornado.These two operators can be overloaded based on both their parameters and their return value.

ExceçõesExceptions

Objetos de exceção devem derivar de System.Exception ou de outro tipo derivado de System.Exception.Exception objects must derive from System.Exception or from another type derived from System.Exception. O exemplo a seguir ilustra o erro do compilador que resulta quando uma classe personalizada chamada ErrorClass é usada para tratamento de exceções.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
'             ~~~~~~~~~~~~~~

Para corrigir este erro, a classe ErrorClass deve herdar de System.Exception.To correct this error, the ErrorClass class must inherit from System.Exception. Além disso, a propriedade Message deve ser substituída.In addition, the Message property must be overridden. O exemplo a seguir corrige esses erros para definir uma classe ErrorClass que seja compatível com 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

AtributosAttributes

Em assemblies do .NET Framework, atributos personalizados fornecem um mecanismo extensível para armazenamento de atributos personalizados e recuperação de metadados sobre objetos de programação, como assemblies, tipos, membros e parâmetros de método.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. Atributos personalizados devem derivar de System.Attribute ou de um tipo derivado de System.Attribute.Custom attributes must derive from System.Attribute or from a type derived from System.Attribute.

O exemplo a seguir viola essa regra.The following example violates this rule. Ele define uma classe NumericAttribute que não deriva de System.Attribute.It defines a NumericAttribute class that does not derive from System.Attribute. Observe que um erro de compilador só acontece quando o atributo não compatível com CLS é aplicado e não quando a classe é definida.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
'     ~~~~~~~~~~~~~

O construtor ou as propriedades de um atributo compatível com CLS podem expor somente os seguintes tipos:The constructor or the properties of a CLS-compliant attribute can expose only the following types:

O exemplo a seguir define uma classe DescriptionAttribute que é derivada de Attribute.The following example defines a DescriptionAttribute class that derives from Attribute. O construtor de classe tem um parâmetro do tipo Descriptor, portanto a classe não é compatível com CLS.The class constructor has a parameter of type Descriptor, so the class is not CLS-compliant. Observe que o compilador do C# emite um aviso, mas compila com êxito, enquanto o compilador do Visual Basic nem emite um aviso ou um erro.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

O atributo CLSCompliantAttributeThe CLSCompliantAttribute attribute

O atributo CLSCompliantAttribute é usado para indicar se um elemento do programa está em conformidade com a Common Language Specification.The CLSCompliantAttribute attribute is used to indicate whether a program element complies with the Common Language Specification. O construtor CLSCompliantAttribute.CLSCompliantAttribute(Boolean) inclui um único parâmetro necessário, isCompliant, que indica se o elemento de programa é compatível com CLS.The CLSCompliantAttribute.CLSCompliantAttribute(Boolean) constructor includes a single required parameter, isCompliant, that indicates whether the program element is CLS-compliant.

No tempo de compilação, o compilador detecta os elementos não compatíveis que provavelmente são compatíveis com CLS e emite um aviso.At compile time, the compiler detects non-compliant elements that are presumed to be CLS-compliant and emits a warning. O compilador não emite avisos para tipos ou membros explicitamente declarados como não compatíveis.The compiler does not emit warnings for types or members that are explicitly declared to be non-compliant.

Os desenvolvedores de componentes podem usar o atributo CLSCompliantAttribute de duas maneiras:Component developers can use the CLSCompliantAttribute attribute in two ways:

  • Para definir as partes da interface pública exposta por um componente que são compatíveis com CLS e as partes que não são compatíveis com 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 o atributo é usado para marcar elementos de programa específicos como compatíveis com CLS, seu uso garante que os elementos sejam acessíveis em todas as linguagens e ferramentas direcionadas ao .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.

  • Para garantir que a interface pública da biblioteca de componentes exponha apenas elementos de programa que são compatíveis com CLS.To ensure that the component library's public interface exposes only program elements that are CLS-compliant. Se os elementos não forem compatíveis com CLS, os compiladores geralmente emitirão um aviso.If elements are not CLS-compliant, compilers will generally issue a warning.

Aviso

Em alguns casos, os compiladores de linguagem aplicam as regras de compatibilidade com CLS independentemente do uso ou não do atributo CLSCompliantAttribute.In some cases, language compilers enforce CLS-compliant rules regardless of whether the CLSCompliantAttribute attribute is used. Por exemplo, definir um membro estático em uma interface viola uma regra CLS.For example, defining a static member in an interface violates a CLS rule. Neste sentido, se você definir um membro static (no C#) ou Shared (no Visual Basic) em uma interface, os compiladores do C# e do Visual Basic exibirão uma mensagem de erro e não compilarão o aplicativo.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.

O atributo CLSCompliantAttribute é marcado com um atributo AttributeUsageAttribute que tem um valor de AttributeTargets.All.The CLSCompliantAttribute attribute is marked with an AttributeUsageAttribute attribute that has a value of AttributeTargets.All. Esse valor permite que você aplique o atributo CLSCompliantAttribute a qualquer elemento de programa, incluindo assemblies, módulos, tipos (classes, estruturas, interfaces, enumerações e delegados), membros de tipo (construtores, métodos, propriedades, campos e eventos), parâmetros, parâmetros genéricos e valores de retorno.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. No entanto, na prática, você deve aplicar o atributo somente a assemblies, tipos e membros de tipo.However, in practice, you should apply the attribute only to assemblies, types, and type members. Caso contrário, os compiladores ignoram o atributo e continuam gerando avisos do compilador sempre que encontrarem um parâmetro não compatível, parâmetro genérico ou valor retornado na interface pública da biblioteca.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.

O valor do atributo CLSCompliantAttribute é herdado pelos elementos contidos no programa.The value of the CLSCompliantAttribute attribute is inherited by contained program elements. Por exemplo, se um assembly for marcado como compatível com CLS, seus tipos também serão compatíveis com CLS.For example, if an assembly is marked as CLS-compliant, its types are also CLS-compliant. Se um tipo for marcado como compatível com CLS, seus membros e tipos aninhados também serão compatíveis com CLS.If a type is marked as CLS-compliant, its nested types and members are also CLS-compliant.

Você pode substituir explicitamente a compatibilidade herdada aplicando o atributo CLSCompliantAttribute a um elemento contido no programa.You can explicitly override the inherited compliance by applying the CLSCompliantAttribute attribute to a contained program element. Por exemplo, é possível usar o atributo CLSCompliantAttribute com um valor isCompliant de false para definir um tipo não compatível em um assembly compatível, e é possível usar o atributo com um valor isCompliant de true para definir um tipo compatível em um assembly não compatível.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. Você também pode definir membros não compatíveis em um tipo compatível.You can also define non-compliant members in a compliant type. No entanto, um tipo não compatível não pode ter membros compatíveis. Portanto, você não pode usar o atributo com um valor isCompliant de true para substituir a herança de um tipo não compatível.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.

Ao desenvolver componentes, você sempre deve usar o atributo CLSCompliantAttribute para indicar se o assembly, seus tipos e membros são compatíveis com 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.

Para criar componentes compatíveis com CLS:To create CLS-compliant components:

  1. Use CLSCompliantAttribute para marcar o assembly como compatível com CLS.Use the CLSCompliantAttribute to mark you assembly as CLS-compliant.

  2. Marque qualquer tipo exposto publicamente no assembly que não seja compatível com CLS como não compatível.Mark any publicly exposed types in the assembly that are not CLS-compliant as non-compliant.

  3. Marque qualquer membro publicamente exposto em tipos compatíveis com CLS como não compatíveis.Mark any publicly exposed members in CLS-compliant types as non-compliant.

  4. Forneça uma alternativa compatível com CLS para membros não compatíveis com CLS.Provide a CLS-compliant alternative for non-CLS-compliant members.

Se você marcou com êxito todos os tipos e membros não compatíveis, o compilador não deverá emitir avisos de não conformidade.If you've successfully marked all your non-compliant types and members, your compiler should not emit any non-compliance warnings. Entretanto, você deve indicar quais membros não são compatíveis com CLS e listar suas alternativas compatíveis com CLS na documentação do produto.However, you should indicate which members are not CLS-compliant and list their CLS-compliant alternatives in your product documentation.

O exemplo a seguir usa o atributo CLSCompliantAttribute para definir um assembly compatível com CLS e um tipo, CharacterUtilities, que tem dois membros não compatíveis com 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. Como ambos os membros são marcados com o atributo CLSCompliant(false), o compilador não produz avisos.Because both members are tagged with the CLSCompliant(false) attribute, the compiler produces no warnings. A classe também fornece uma alternativa compatível com CLS para ambos os métodos.The class also provides a CLS-compliant alternative for both methods. Normalmente, nós adicionaríamos apenas duas sobrecargas ao método ToUTF16 para fornecer alternativas compatíveis com CLS.Ordinarily, we would just add two overloads to the ToUTF16 method to provide CLS-compliant alternatives. Entretanto, como os métodos não podem ser sobrecarregados com base no valor retornado, os nomes dos métodos compatíveis com CLS são diferentes dos nomes dos métodos não compatíveis.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 você estiver desenvolvendo um aplicativo em vez de uma biblioteca (ou seja, se não estiver expondo tipos ou membros que possam ser consumidos por outros desenvolvedores de aplicativos), a conformidade com CLS dos elementos do programa que seu aplicativo consome só serão de interesse se sua linguagem não der suporte a eles.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. Nesse caso, seu compilador de linguagem gerará um erro quando você tentar usar um elemento não compatível com CLS.In that case, your language compiler will generate an error when you try to use a non-CLS-compliant element.

Interoperabilidade em qualquer idiomaCross-Language Interoperability

A independência de linguagem tem vários significados possíveis.Language independence has a number of possible meanings. Um significado, discutido no artigo Independência de linguagem e componentes independentes de linguagem, envolve o consumo pleno de tipos escritos em uma linguagem de um aplicativo escrito em outra linguagem.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. Um segundo significado, que é o enfoque deste artigo, envolve combinar o código gravado em várias linguagens em um único assembly do .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.

O exemplo a seguir ilustra a interoperabilidade em qualquer idioma com a criação de uma biblioteca de classes chamada Utilities.dll que inclui duas classes, 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. A classe NumericLib é gravada em C#, e a classe StringLib é gravada em Visual Basic.The NumericLib class is written in C#, and the StringLib class is written in Visual Basic. Aqui está o código-fonte de StringUtil.vb, que inclui um único membro, ToTitleCase, em sua 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

Aqui está o código-fonte de NumberUtil.cs, que define uma classe NumericLib com dois membros, 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; 
   }
}

Para empacotar as duas classes em um único assembly, você deve compilá-las em módulos.To package the two classes in a single assembly, you must compile them into modules. Para compilar o arquivo de código-fonte do Visual Basic em um módulo, use este comando:To compile the Visual Basic source code file into a module, use this command:

vbc /t:module StringUtil.vb

Para obter mais informações sobre a sintaxe de linha de comando do compilador do Visual Basic, consulte Compilando através da linha de comando.For more information about the command-line syntax of the Visual Basic compiler, see Building from the Command Line.

Para compilar o arquivo de código-fonte do C# em um módulo, use este comando:To compile the C# source code file into a module, use this command:

csc /t:module NumberUtil.cs

Para obter mais informações sobre a sintaxe de linha de comando do compilador do C#, consulte Compilando na linha de comando com csc.exe.For more information about the command-line syntax of the C# compiler, see Command-line Building With csc.exe.

Então você usa as Opções do vinculador para compilar os dois módulos em um assembly:You then use the Linker options to compile the two modules into an assembly:

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

O exemplo a seguir chama os métodos NumericLib.NearZero e StringLib.ToTitleCase.The following example then calls the NumericLib.NearZero and StringLib.ToTitleCase methods. Observe que o código do Visual Basic e o código do C# podem acessar os métodos em ambas as classes.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

Para compilar o código do Visual Basic, use este comando:To compile the Visual Basic code, use this command:

vbc example.vb /r:UtilityLib.dll

Para compilar usando C#, altere o nome do compilador de vbc para csc e altere a extensão do arquivo de .vb para .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

Consulte tambémSee also