2009-09-24 5 views
2

I modifié la méthode d'extension Thorarin a donné en réponse à this question de travailler sur un int au lieu d'une chaîne:Int jeté erreur dans l'extension générique

public static TEnum ToEnum<TEnum>(this int intEnumValue, TEnum defaultValue) 
{ 
    if (!Enum.IsDefined(typeof(TEnum), intEnumValue)) 
     return defaultValue; 
    return (TEnum)intEnumValue; 
} 

Le compilateur donne l'erreur « Impossible de convertir le type « int » à 'TEnum'. " sur la dernière ligne.

Si la ligne est modifiée à ceci:

return (TEnum)(object)intEnumValue; 

compile et fonctionne.

Pourquoi l'int doit-il être converti en objet en premier?

Répondre

5

Il est impossible de convertir directement un int en un type inconnu, donc le compilateur n'autorisera pas (TEnum)intEnumValue. Les deux moulages vous faites maintenant sont en fait subtilement différentes: (object) boîtes du int, tandis que (TEnum) jette l'int boxed à un TEnum, statiquement permis parce qu'une expression est de type statique object peut effectivement être de type d'exécution TEnum.

Il pourrait également y avoir une autre subtilité: Normalement, une boîte intcan only be unboxed to int. Je pense que j'ai expliqué pourquoi la conversion est autorisée par le compilateur, mais pas pourquoi c'est aussi autorisé par le runtime. Peut-être que la conversion en TEnum est uniquement autorisée au moment de l'exécution car TEnum se trouve être une énumération dont le type de base est int? Je pense que je me souviens avoir lu que les enums du CLR ne sont en réalité que des exemples de leur type de base.

Edit: Je confirmé mes soupçons:

public static void Main() 
{ 
    int value = 1; 

    IntEnum i = ToEnum<IntEnum>(value); // Valid cast, runs fine. 
    ByteEnum b = ToEnum<ByteEnum>(value); // Invalid cast exception! 
} 

public enum ByteEnum : byte { } 

public enum IntEnum : int { } 

public static TEnum ToEnum<TEnum>(int value) 
{ 
    return (TEnum)(object)value; 
} 

donc on peut dire que (TEnum) sur une boîte int est valable uniquement si TEnum est en fait une int sous les couvertures!

+0

Existe-t-il une méthode plus directe pour passer d'un type sous-jacent d'Enum à l'Enum? –

+1

Enum.ToObject (typeof (TEnum), intEnumValue) en tant que TEnum – plinth

0

Lorsque vous lancez avec (TEnum) intEnumValue, le compilateur ne sait pas quel type de classe TEnum va être. Puisque int ne peut être implicitement converti en certaines classes, le compilateur échoue. La conversion en objet est acceptable, et TEnum est un objet, de sorte que la conversion est également possible.

0

TEnum est un type arbitraire. Pouvez-vous lancer un int à Rectangle? À DateTime? Le compilateur ne sait pas et malheureusement la spécification dit que vous ne pouvez pas ajouter une contrainte non plus.

2

Eric Lippert a publié un billet sur ce type de numéro here. Fondamentalement, il existe plusieurs types de 'cast', et aller de int à TEnum pourrait être l'un des nombreux. Donc, le seul moyen sûr de le faire est de placer l'int dans un objet, puis de le convertir en un TEnum lors de l'exécution. Vous ne pouvez pas passer directement d'int à TEnum, car ce qui doit être fait dépend de ce qu'est TEnum, et cela n'est connu qu'à l'exécution.

Questions connexes