2009-12-09 7 views
4

Je me demande pourquoi une seule conversion implicite en valeur enum ne fonctionne pas de la même façon que si la conversion était en Type de système. Je ne vois pas de raison technique mais peut-être que quelqu'un de plus intelligent que moi peut me faire la lumière.Pourquoi ne puis-je pas activer une classe avec une seule conversion implicite en une énumération?

Le tableau suivant ne peut pas être compilé avec, "A value of an integral type expected" et "Cannot implicitly convert type 'Test.En' to 'Test.Foo".

void test1(){ 
    Foo f = new Foo(); 

    switch (f)   // Comment this line to compile 
    //switch ((En)f) // Uncomment this line to compile 
    { 
     case En.One: 
      break; 
    } 
} 


////////////////////////////////////////////////////////////////// 

public enum En 
{ 
    One, 
    Two, 
    Three, 
} 

public class Foo 
{ 
    En _myEn; 

    public static implicit operator En(Foo f) 
    { 
     return f._myEn; 
    } 
} 

modifier de la spécification:

Le directeur type d'une instruction switch est établie par l'expression du commutateur. Si le type de l'expression du commutateur est sbyte, octet, short, ushort, int, uint, long, ulong, char, chaîne ou un type enum, alors c'est le type régissant l'instruction switch. Sinon, exactement une conversion implicite définie par l'utilisateur (§6.4) doit exister du type de l'expression du commutateur à l'un des types suivants possibles: sbyte, octet, court, ushort, int, uint, long, ulong, char, chaîne. Si aucune conversion implicite n'existe, ou si plus d'une telle conversion implicite existe, une erreur de compilation se produit.

Pour clarifier la question, pourquoi est un type ENUM pas inclus dans la liste des permis conversion implicite définies par l'utilisateur s?

+0

cas Foo.En.One? Besoin de voir le reste de votre code mais cela ressemble à un simple cas de spécification correcte des noms de types. –

+0

Parce que vous ne devriez pas être paresseux :) – leppie

+0

Où est Eric Lippert quand vous avez besoin de lui? :) – jasonh

Répondre

5

Les archives de notes de conception de langage ne justifient pas cette décision. C'est malheureux, puisque la décision a été changée. Comme vous pouvez le voir, la conception a évolué au fil du temps:

Notes du 26 mai 1999:

Quels types sont autorisés en tant que l'argument à une instruction switch? types intégraux incluant char, enum types, bool. C# permet aussi des types qui peuvent être implicitement et convertis sans ambiguïté à l'un des types mentionnés ci-dessus. (S'il y a conversion implicite multiple, puis son ambigu et une erreur de compilation se produit.) Nous ne sommes pas sûrs que nous voulons soutenir la chaîne ou pas.

7ème Juin, 1999

Nous avons discuté permettant Enclencher chaîne arguments. Nous pensons que cela est une bonne caractéristique - la langue peut ajouter de la valeur en faisant ce cas commun plus facile à écriture et la complexité supplémentaire pour l'utilisateur est très faible.

20ème Décembre, 1999

Il est illégal de changer une expression de type bool. Il est possible d'activer l'expression d'un type intégral ou d'un type de chaîne. Il est de passer juridique une expression d'un type qui a exactement une conversion implicite à un type intégral ou type de chaîne.

Ici, nous avons la première occurrence de la règle en question. Les Enums semblent avoir disparu. Et pourquoi ne pas utiliser les conversions implicites définies par l'utilisateur pour enum? Était-ce simplement un oubli? Les concepteurs n'ont pas enregistré leurs pensées.

Notez que la première phrase est pas ce que nous avons mis. Il n'est pas clair pour moi pourquoi les réalisateurs ont fait le contraire de ce que le comité de conception a recommandé. Cela revient à nouveau dans les notes plusieurs années plus tard:

13 Août, 2003

Le compilateur permet de passer sur bool. Ne pas documenter cela et l'ajouter à la langue. Ne pas vouloir supprimer pour des raisons de compatibilité. Décidé pour continuer silencieusement à prendre en charge le commutateur sur bool. J'ai décidé que c'était stupide;

Lorsque nous avons produit l'édition imprimée annotée de la spécification C# 3.0, j'ai ajouté bool (et bool?) à la liste des types de gouvernance légale.

En bref: le tout est un peu un gâchis. Je ne sais pas pourquoi les enums étaient dedans, puis dehors, puis demi-out-out. Cela pourrait devoir rester l'un des mystères de l'inconnu.

+0

Juste par curiosité, pourquoi le compilateur C# transforme-t-il la conversion explicite en une conversion implicite en écrivant le MSIL au lieu d'un explicit comme l'utilisateur écrit? – jasonh

+0

Je ne comprends pas la question. Pouvez-vous donner un exemple? Peut-être que l'ouverture d'une nouvelle question serait appropriée. –

+0

Eh bien, si vous compilez ce qui suit: 'switch ((En) f)', le compilateur va émettre l'instruction IL suivante 'call valuetype Test/En Test/Foo :: op_Implicit (classe Test/Foo)'. Ma question est, pourquoi le compilateur choisit-il d'utiliser une instruction implicite de conversion IL au lieu d'une instruction explicite, comme l'utilisateur a écrit: 'switch ((En) f)' – jasonh

-1

Jetez un coup d'œil à ce deuxième message d'erreur. Le compilateur essaie de forcer l'énumération pour qu'elle corresponde au type de l'instruction switch.

À titre de point d'intérêt, comment cela se passe-t-il?

void test2(){ 
    Foo f = new Foo(); 

    switch (En.One) 
    { 
     case f: 
      break; 
    } 
} 
+2

Cela échouera puisque le cas doit être suivi d'une expression constante. –

2

Parce que les énumérations sont traités comme des entiers aux fins de commutation, et comme je l'ai demandé avant, the compiler doesn't do multiple implicit conversions to get to a usable type, il ne peut pas comprendre comment allumer foo. Ma seule théorie sur la raison pour laquelle les énumérations ne peuvent pas être utilisées de la sorte est que les énumérations ne sont pas un type entier en soi, et donc le compilateur devrait effectuer plusieurs conversions implicites pour atteindre une primitive entière de foo. .

Je compilé puis réfléchissais votre code et voici les résultats:

public static void Main() 
{ 
    Foo f = new Foo(); 
    f._myEn = En.Three; 
    switch (f) 
    { 
     case En.One: 
     { 
     } 
    } 
} 

Donc, apparemment sous les couvertures, il ne fait une conversion implicite. : S

+2

"Étant donné que les enums sont traités comme des entiers dans le but de basculer" - si vous pensez qu'il existe une conversion réelle (en termes de sémantique du langage, pas les détails d'implémentation de VC#), veuillez citer la spécification. –

+0

Je ne trouve rien dans la spécification à ce sujet, mais c'est mon meilleur * guess *. Reflector m'a donné des choses intéressantes en décompilant ceci, et je posterai mes résultats là-dessus. – RCIX

+0

Voulez-vous dire quand vous reflétez la version compilée, en utilisant une distribution explicite dans le commutateur "switch ((En) f)", ça ressemble à ça? –

-1

Et si votre classe contenait deux énumérations et avait des opérateurs de conversion implicites pour les deux? Ou mieux encore, que se passerait-il si vous aviez des opérateurs de conversion implicites pour un enum et un int? Quelle conversion le compilateur sélectionnera-t-il automatiquement pour vous lorsque vous écrivez une instruction switch?

Vous devez spécifier explicitement quel type d'objet est utilisé dans l'instruction switch. Les opérateurs implicites disent simplement au compilateur/runtime "si vous avez un Foo et avez besoin d'un En, ce code le fait". Cela ne change pas le type sous-jacent de l'objet.

+0

Je m'attendrais à ce que la compilation échoue, Sur la base de '... exactement une conversion implicite définie par l'utilisateur (§6.4) doit exister ...' être violé. –

0
void test1(){ 
    Foo f = new Foo(); 
    En n = f; 

    switch (n) 
    { 
     case En.One: 
      break; 
    } 
} 

EDIT: Depuis switch attend une valeur intégrale, l'écriture switch(f) rend le regard du compilateur pour la conversion d'une instance de Foo à un type intégral, qui n'existe pas.

Questions connexes