Compartilhar via


Tipo Enum CLR

A declaração e o comportamento de enums foi alterado de Managed Extensions for C++ para Visual C++.

Declaração de enum gerenciado extensões é precedida de __value palavra-chave.A idéia aqui é distinguir enum nativo de enum CLR que é derivado de System::ValueType, ao mesmo tempo, sugerindo uma funcionalidade semelhante.Por exemplo:

__value enum e1 { fail, pass };
public __value enum e2 : unsigned short  { 
   not_ok = 1024, 
   maybe, ok = 2048 
};

A nova sintaxe resolve o problema de distinguir nativos e CLR enums, enfatizando a natureza de classe do último vez suas raízes de tipo de valor.Como tal, o __value palavra-chave é descartado, substituído com o par de palavra-chave espaçados de enum class.Isso fornece uma simetria par de palavra-chave para as declarações da referência, valor e classes de interface:

enum class ec;
value class vc;
ref class rc;
interface class ic;

A tradução do par de enumeração de e1 e e2 a nova sintaxe é da seguinte maneira:

enum class e1 { fail, pass };
public enum class e2 : unsigned short { 
   not_ok = 1024,
   maybe, ok = 2048 
};

Além dessa alteração sintática pequena, o comportamento do tipo enum CLR foi alterado de várias maneiras:

  • Declaração de encaminhamento de um enum CLR não é mais suportada.Não há nenhum mapeamento.Ele simplesmente está sinalizado como um erro de tempo de compilação.
__value enum status; // Managed Extensions: ok
enum class status;   // new syntax: error
  • Resolução de sobrecarga entre os tipos de aritméticos internos e o Object a hierarquia de classe inverteu entre as versões de idioma de dois!Como um efeito colateral enums CLR não implicitamente são convertidos em tipos de aritméticos.

  • A nova sintaxe, um enum CLR mantém seu próprio escopo, não é o caso de extensões gerenciadas.Anteriormente, os enumeradores estavam visíveis dentro do escopo que contém o enum.Agora, os enumeradores são encapsulados dentro do escopo de enum.

Enums CLR são um tipo de objeto

Considere o fragmento de código a seguir:

__value enum status { fail, pass };

void f( Object* ){ Console::WriteLine("f(Object)\n"); }
void f( int ){ Console::WriteLine("f(int)\n"); }

int main()
{
   status rslt = fail;

   f( rslt ); // which f is invoked?
}

Para o programador de C++ nativo, o natural de resposta à pergunta de qual instância do sobrecarregado f() é invocado é o de f(int).Enum é uma constante de integral simbólica e ele participa promoções integrais padrão que têm precedência nesse caso.E, na verdade no Managed Extensions estava a instância à qual a chamada resolve.Isso causou um número de surpresas – não quando é usado em um nativo C++ de espírito – mas precisamos interagir com a estrutura existente de BCL (Base Class Library), onde um Enum é uma classe indiretamente derivada de Object.No Visual C++ design de linguagem, a instância de f() invocado é o de f(Object^).

A maneira de Visual C++ optou por impor isso é não oferecer suporte a conversões implícitas entre um tipo de enum CLR e tipos de aritméticos.Isso significa que qualquer atribuição de um objeto de tipo enum CLR para um tipo de aritmético exigirá uma conversão explícita.Assim, por exemplo, dada

void f( int );

como um método sobrecarregado não em extensões gerenciadas, a chamada

f( rslt ); // ok: Managed Extensions; error: new syntax

é ok e o valor contido em rslt implicitamente é convertido em um valor inteiro.Em Visual C++, essa chamada falha compilar.Traduzi-la corretamente, deve inserir um operador de conversão:

f( safe_cast<int>( rslt )); // ok: new syntax

O escopo do tipo Enum CLR

Uma das alterações entre as linguagens c e C++ foi a adição em C++ do escopo do recurso struct.Em C, uma struct é apenas um agregado sem suporte de uma interface ou um escopo associado de dados.Isso foi uma mudança radical no momento e foi um problema para muitos usuários C++ novos proveniente da linguagem c de contenciosos.O relacionamento entre o nativo e enum CLR é análogo.

Extensões gerenciadas, foi feita uma tentativa para definir nomes levemente injetados para enumeradores de um enum CLR para simular a ausência de escopo enum nativo.Isso prova bem-sucedida.O problema é que isso faz com que os enumeradores derrubar no namespace global, resultando em difícil gerenciar conflitos de nome.Na sintaxe de novo, podemos ter conformed para outras linguagens do CLR para oferecer suporte a escopos enum CLR.

Isso significa que qualquer uso não qualificado de um enumerador de um enum CLR não será reconhecido pela nova sintaxe.Vejamos um exemplo real.

// Managed Extensions supporting weak injection
__gc class XDCMake {
public:
   __value enum _recognizerEnum { 
      UNDEFINED,
      OPTION_USAGE, 
      XDC0001_ERR_PATH_DOES_NOT_EXIST = 1,
      XDC0002_ERR_CANNOT_WRITE_TO = 2,
      XDC0003_ERR_INCLUDE_TAGS_NOT_SUPPORTED = 3,
      XDC0004_WRN_XML_LOAD_FAILURE = 4,
      XDC0006_WRN_NONEXISTENT_FILES = 6,
   };

   ListDictionary* optionList;
   ListDictionary* itagList;

   XDCMake() {
      optionList = new ListDictionary;

      // here are the problems …
      optionList->Add(S"?", __box(OPTION_USAGE)); // (1)
      optionList->Add(S"help", __box(OPTION_USAGE)); // (2)

      itagList = new ListDictionary;
      itagList->Add(S"returns", 
         __box(XDC0004_WRN_XML_LOAD_FAILURE)); // (3)
   }
};

Cada um dos três não qualificado usa os nomes de enumerador ((1), (2), e (3)) precisará ser qualificado na tradução para a nova sintaxe para o código fonte compilar.Aqui está uma tradução correta do código fonte original:

ref class XDCMake {
public:
   enum class _recognizerEnum {
      UNDEFINED, OPTION_USAGE, 
      XDC0001_ERR_PATH_DOES_NOT_EXIST = 1,
      XDC0002_ERR_CANNOT_WRITE_TO = 2,
      XDC0003_ERR_INCLUDE_TAGS_NOT_SUPPORTED = 3,
      XDC0004_WRN_XML_LOAD_FAILURE = 4,
      XDC0006_WRN_NONEXISTENT_FILES = 6
   };

   ListDictionary^ optionList;
   ListDictionary^ itagList;

   XDCMake() {
      optionList = gcnew ListDictionary;
      optionList->Add("?",_recognizerEnum::OPTION_USAGE); // (1)
      optionList->Add("help",_recognizerEnum::OPTION_USAGE); //(2)
      itagList = gcnew ListDictionary;
      itagList->Add( "returns", 
         _recognizerEnum::XDC0004_WRN_XML_LOAD_FAILURE); //(3)
   }
};

Isso altera a estratégia de design entre um nativo e um enum CLR.Com um enum CLR mantém um escopo associado em Visual C++, necessário nem eficaz encapsular a declaração de enum dentro de uma classe.Este idioma evoluiu perto da hora do cfront 2.0 no Bell Laboratories também para solucionar o problema de poluição de nome global.

Na versão original do beta da nova biblioteca de iostream por Jerry Schwarz na Bell Laboratories, a Jerry não encapsular todos os enums associados definidos para a biblioteca e os enumeradores comuns, como read, write, appende assim por diante, tornou quase impossível para os usuários compilar seu código existente.Uma solução teria sido desconfiguram os nomes, como io_read, io_write, etc.Uma segunda solução seria modificar o idioma, adicionando o escopo para um enum, mas isso não era praticável de acordo com o momento.A solução intermediária foi encapsular enum dentro da classe ou classe de hierarquia, onde o nome da marca e os enumeradores do enum preencher o escopo delimitador de classe.) Ou seja, a motivação para colocar enums dentro de classes, pelo menos originalmente, não era filosóficas, mas uma resposta prática para o problema da poluição do espaço de nome global.

Com o Visual C++ enum, não há qualquer benefício atraente para encapsular um enum dentro de uma classe.Na verdade, se você olhar o System namespaces, você verá que enumerações, classes e interfaces habitam o mesmo espaço de declaração.

Consulte também

Referência

classe enum (Extensões de Componentes C++)

Conceitos

Tipos de valor e seus comportamentos (C++/CLI)