Je suis curieux de savoir pourquoi le compilateur C # ne me donne qu’un message d’erreur pour la deuxième instruction if.
enum Permissions : ulong { ViewListItems = 1L, } public void Method() { int mask = 138612833; int compare = 32; if (mask > 0 & (ulong)Permissions.ViewListItems > 32) { //Works } if (mask > 0 & (ulong)Permissions.ViewListItems > compare) { //Operator '>' cannot be applied to operands of type 'ulong' and 'int' } }
J’ai expérimenté cela en utilisant ILSpy pour examiner le résultat, et c’est ce que j’ai découvert.
Évidemment, dans votre deuxième cas, il s’agit d’une erreur – vous ne pouvez pas comparer un ulong
et un int
car il n’y a pas de type auquel vous pouvez contraindre les deux. Un ulong
peut être trop gros pour un long
et un int
peut être négatif.
Dans votre premier cas, cependant, le compilateur est malin. Il se rend compte que const 1
> const 32
n’est jamais vrai et n’inclut pas votre instruction if
dans la sortie compilée. (Cela devrait donner un avertissement pour le code inaccessible.) C’est la même chose si vous définissez et utilisez un const int
plutôt qu’un littéral, ou même si vous convertissez le littéral explicitement (c’est-à-dire (int)32
).
Mais alors le compilateur ne réussit-il pas à comparer un ulong
avec un int
, ce qui, nous l’avons dit, était impossible?
Apparemment non. Alors qu’est – ce qui se passe?
Essayez plutôt de faire quelque chose dans les lignes suivantes. (Prendre les entrées et écrire les sorties pour que le compilateur ne comstack rien.)
const int thirtytwo = 32; static void Main(ssortingng[] args) { ulong x = ulong.Parse(Console.ReadLine()); bool gt = x > thirtytwo; Console.WriteLine(gt); }
Cela comstackra, même si ulong
est une variable et même si le résultat n’est pas connu au moment de la compilation. Jetez un coup d’œil à la sortie dans ILSpy:
private static void Main(ssortingng[] args) { ulong x = ulong.Parse(Console.ReadLine()); bool gt = x > 32uL; /* Oh look, a ulong. */ Console.WriteLine(gt); }
Ainsi, le compilateur traite en fait votre const int
comme un ulong
. Si vous faites thirtytwo = -1
, la compilation du code échoue, même si nous soaps alors que gt
sera toujours vrai. Le compilateur lui-même ne peut pas comparer un ulong
à un int
.
Notez également que si vous faites x
un long
au lieu d’un ulong
, le compilateur génère 32L
lieu de 32
sous forme d’entier, même s’il n’est pas obligé de le faire. (Vous pouvez comparer un int
et un long
au moment de l’exécution.)
Cela indique que le compilateur ne traite pas 32
comme un ulong
dans le premier cas, car il doit le faire, simplement parce qu’il peut correspondre au type de x
. Cela évite au temps d’exécution de contraindre la constante, et il ne s’agit que d’un bonus lorsque la contrainte ne devrait pas être possible de plein droit.
Ce n’est pas le CLR donnant ce message d’erreur, c’est le compilateur.
Dans votre premier exemple, le compilateur traite 32
comme ulong
(ou un type implicitement convertible en ulong
par exemple uint
), tandis que dans votre deuxième exemple, vous avez explicitement déclaré le type sous la forme d’un int
. Il n’y a pas de surcharge de l’opérateur >
qui accepte un ulong
et un int
et vous obtenez donc une erreur du compilateur.
Les réponses de rich.okelly et de rawling expliquent correctement pourquoi vous ne pouvez pas les comparer directement. Vous pouvez utiliser la méthode ToUInt64 de la classe Convert pour promouvoir l’int.
if (mask > 0 & (ulong)Permissions.ViewListItems > Convert.ToUInt64(compare)) { }