Je pense que cette question va m'apporter une gloire instantanée ici sur Stack Overflow.
Supposons que vous ayez le type suivant :
// represents a decimal number with at most two decimal places after the period
struct NumberFixedPoint2
{
decimal number;
// an integer has no fractional part; can convert to this type
public static implicit operator NumberFixedPoint2(int integer)
{
return new NumberFixedPoint2 { number = integer };
}
// this type is a decimal number; can convert to System.Decimal
public static implicit operator decimal(NumberFixedPoint2 nfp2)
{
return nfp2.number;
}
/* will add more nice members later */
}
Il a été écrit de telle sorte que seules les conversions sûres qui ne perdent pas en précision sont autorisées. Cependant, lorsque j'essaie ce code :
static void Main()
{
decimal bad = 2.718281828m;
NumberFixedPoint2 badNfp2 = (NumberFixedPoint2)bad;
Console.WriteLine(badNfp2);
}
Je suis surpris que cela compile et, quand on l'exécute, écrit 2
. La conversion de int
(de valeur 2
) à NumberFixedPoint2
est important ici. (Une surcharge de WriteLine
qui prend en compte un System.Decimal
est préférable, au cas où quelqu'un se poserait la question).
Pourquoi diable la conversion de decimal
a NumberFixedPoint2
autorisé ? (A propos, dans le code ci-dessus, si NumberFixedPoint2
passe d'un struct à une classe, rien ne change).
Savez-vous si la spécification du langage C# dit qu'une conversion implicite de int
à un type personnalisé "implique" l'existence d'une conversion explicite "directe" de decimal
à ce type personnalisé ?
Cela devient bien pire. Essayez plutôt ce code :
static void Main()
{
decimal? moreBad = 7.3890560989m;
NumberFixedPoint2? moreBadNfp2 = (NumberFixedPoint2?)moreBad;
Console.WriteLine(moreBadNfp2.Value);
}
Comme vous le voyez, nous avons (soulevé) Nullable<>
conversions ici. Mais oh oui, ça se compile.
Lorsqu'il est compilé en x86 "plateforme", ce code écrit une valeur numérique imprévisible. Laquelle varie de temps en temps. Par exemple, à une occasion, j'ai obtenu 2289956
. Ça, c'est un sérieux bug !
Lorsqu'il est compilé pour le x64 le code ci-dessus fait planter l'application avec un message de type System.InvalidProgramException
avec message Common Language Runtime a détecté un programme invalide. Selon la documentation de l InvalidProgramException
classe :
En général, cela indique un bogue dans le compilateur qui a généré le programme.
Quelqu'un (comme Eric Lippert, ou quelqu'un qui a travaillé avec des conversions liftées dans le compilateur C#) connaît-il la cause de ces bogues ? Par exemple, quelle est la condition suffisante pour que nous ne les rencontrions pas dans notre code ? Parce que le type NumberFixedPoint2
est en fait quelque chose que nous avons dans le code réel (gérer l'argent d'autres personnes et autres).