Aracılığıyla paylaş


CLR Enum Türü

Numaralandırmaların bildirim ve davranışları C++ için Yönetilen Uzantılardan Visual C++ 2010 öğesine değişmiştir.

Yönetilen Uzantılar numaralandırma bildiriminin önüne __value anahtar kelimesi gelir. Buradaki amaç benzer bir işlevsellik önerirken yerel numaralandırmayı System::ValueType öğesinden oluşturulan CLR numaralandırmasından ayırmaktır. Örneğin:

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

Yeni sözdizimi, yerel ve CLR numaralandırmalarını ayırt etme sorununu ikincinin değer türü kökleri yerine sınıf yapısını vurgulayarak çözer. Bu yüzden, __value anahtar kelimesi atılır ve yerini enum class aralıklı anahtar çifti alır. Bu başvuru, değer ve arabirim sınıflarının bildirimlerine çiftli bir anahtar kelime simetrisi sağlar.

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

Yeni sözdiziminde e1 ve e2 çiftinin numaralandırılmasının çevirisi aşağıdaki gibi görünür:

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

Bu küçük sözdizimi değişikliğinden ayrı olarak, CLR numaralandırma türünün davranışı çeşitli yollarla değişmiştir:

  • CLR numaralandırmasının ileriye dönük bildirimi artık desteklenmemektedir. Eşleştirme mevcut değil. Derleme zamanı hatası olarak işaretlenmiştir.
__value enum status; // Managed Extensions: ok
enum class status;   // new syntax: error
  • Yerleşik aritmetik türleri ve Object sınıfı hiyerarşisi arasında aşırı yükleme çözünürlüğü iki dil sürümü arasında ters çevrilmiştir! Yan etki olarak, CLR numaralandırmaları artık dolaylı olarak aritmetik türlere dönüştürülmez.

  • Yeni sözdiziminde, CLR numaralaması kendi kapsamını tutar, ve bu Yönetilen Uzantılar için böyle değildir. Numaralandırıcılar daha önce, numaralandırmanın kapsama alanı içinde görünür durumdaydı. Bundan sonra, numaralandırıcılar numaralandırma kapsamına girer.

CLR Numaralandırmaları bir Nesne Türüdür

Aşağıdaki kodu bölümünü gözden geçirin:

__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?
}

Yerel C++ programcısı için, hangi aşırı yüklenmiş f() örneğinin çağrıldığı sorusunun doğal yanıtı budur: f(int). Enum, sembolik bir tam sayı sabitidir ve bu durumda öncelikli standart tam sayı yükseltmelerine katılır. Ve aslında Yönetilen Uzantılar'da bu, çağrının çözümlediği örnek olmuştur. Biz onları yerel bir C++ akıl çerçevesinde kullandığımızda değil- ancak onlara Enum öğesinin Object öğesinden dolaysız olarak türetildiği bir sınıf olan varolan BCL (Temel Sınıf Kitaplığı) çerçevesiyle etkileşim için ihtiyaç duyduğumuzda - bu bir takım sürprizlere neden olur. Visual C++ 2010 dil tasarımında, çağrılan f() örneği f(Object^) öğesinindir.

Visual C++ 2010 yolu CLR enum türü ile aritmetik türler arasındaki örtülü dönüştürmeleri desteklememek için bunu uygulamayı seçer. Buna göre bir CLR numaralandırma türü nesnesinin bir aritmetik türe herhangi bir atanması açık bir dönüştürme gerektirebilir. Bu nedenle, örneğin,

void f( int );

Yönetilen Uzantılar'da aşırı yüklenme olmayan bir yöntem olarak, çağrı

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

tamamdır ve rslt içinde barındırılan değer örtülü olarak bir tamsayı değerine dönüştürülür. Visual C++ 2010 öğesinde, bu çağrının derlemesi başarısız olur. Doğru bir şekilde çevirmek için bir dönüştürme işleci eklemeliyiz:

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

CLR Enum Türü Kapsamı

C ve C++ dilleri arasındaki değişikliklerden biri, yapı özelliğindeki kapsamın C++ dilindeki ek olmasıdır. C'de, bir yapı bir arabirimin ya da bir ilişkili kapsamın desteği olmadan yalnızca veri toplamasıdır. Bu zamanında oldukça radikal bir değişiklikti ve C dilinden gelen bir çok yeni C++ kullanıcıları için tartışmalı bir konuydu. Yerel ve CLR enum arasındaki ilişki benzerdir.

Yönetilen Uzantılar'da, yerli numaralama içindeki kapsamın yokluğunun benzetimini yapmak için CRL enum numaralandırıcıları zayıf enjekte adlarını tanımlamak için bir girişimde bulunuldu. Bu başarılı olmamıştır. Sorun, bunun numaralandırıcıların genel ad alanına serpilmesine sebep olur, ad çakışmalarının üstesinden gelmek zor bir hal alır. Yeni sözdizimini CLR enum desteği kapsamında bulunan diğer CLR dillerine uygun hale getirdik.

Buna göre bir CLR numaralandırmasının herhangi bir niteliksiz kullanımı yeni sözdizimi tarafından tanınmayacaktır. Gerçek durum örneğine bakalım.

// 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)
   }
};

Numaralandırıcı adlarının nitelendirilmemiş üç kullanımının her birinin ((1), (2), ve (3)) kaynak kodun derleyebilmesi için yeni sözdizimine çeviri konusunda nitelendirilmesi gerekir. Özgün kaynak kodunun doğru çevirisi aşağıdadır:

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)
   }
};

Bu bir yerel ve bir CLR numaralandırma arasında tasarım stratejisini değiştirir. Visual C++ 2010 öğesinin içindeki ilişkili kapsamı sürdüren CLR numaralaması ile, söz konusu öğe bir sınıftaki numaralama açıklamasını yalıtmak için gerekli ve etkili değildir. Bu deyim, küresel ad kirliliği sorununu da çözmek amacıyla Bell Laboratories dahilinde, yaklaşık olarak cfront 2.0 ile aynı zamanlarda geliştirilmiştir.

Bell Laboratuarları'ndan Jerry Schwarz tarafından oluşturulan yeni iostream kitaplığının özgün beta sürümünde, Jerry kitaplık için tanımlanmış olan bütün ilişkili numaraları kapsüllemedi ve bu sebepten read, write, append, vb gibi genel numaralandırıcılar kullanıcıların kendi varolan kodlarını derlemelerini neredeyse imkansız kıldı. Çözümlerden biri, io_read, io_write vb. gibi adları değiştirmek olabilirdi. İkinci bir çözüm enuma kapsam ekleyerek dili değiştirmek olabilirdi, ancak bu o zaman için elverişli değildi. Orta çözüm, numaralandırmanın hem etiket adını hem de numaralandırıcısını çevreleyen sınıf kapsamının doldurulduğu sınıf ya da sınıf hiyerarşisinde numaralandırmayı yalıtmaktı. Yani, sınıflar arasına numaralandırmalar yerleştirmenin nedeni, en azından orijinalde, küresel isim-alan kirliliği problemine düşüncede değil pratikte verilmiş bir yanıttır.

Visual C++ 2010 numaralaması ile, bir sınıf içindeki numaralamayı yalıtmanın önemli bir faydası yoktur. System ad alanlarına bakarsanız çetelelerin, sınıfların ve arabirimlerin aynı bildirim alanında bulunduğunu göreceksiniz.

Ayrıca bkz.

Başvuru

enum class

Kavramlar

Değer Türleri ve Davranışları