Le code suivant entraîne l' utilisation de la variable locale non attribuée "numberOfGroups" :
int numberOfGroups;
if(options.NumberOfGroups == null || !int.TryParse(options.NumberOfGroups, out numberOfGroups))
{
numberOfGroups = 10;
}
Cependant, ce code fonctionne bien (cependant, ReSharper dit que le = 10
est redondant):
int numberOfGroups = 10;
if(options.NumberOfGroups == null || !int.TryParse(options.NumberOfGroups, out numberOfGroups))
{
numberOfGroups = 10;
}
Est-ce que je manque quelque chose ou est-ce que le compilateur n'aime pas mon ||
?
J'ai réduit cela à la dynamic
cause des problèmes ( options
c'était une variable dynamique dans mon code ci-dessus). La question demeure, pourquoi je ne peux pas faire ça ?
Ce code ne compile pas :
internal class Program
{
#region Static Methods
private static void Main(string[] args)
{
dynamic myString = args[0];
int myInt;
if(myString == null || !int.TryParse(myString, out myInt))
{
myInt = 10;
}
Console.WriteLine(myInt);
}
#endregion
}
Cependant, ce code fait :
internal class Program
{
#region Static Methods
private static void Main(string[] args)
{
var myString = args[0]; // var would be string
int myInt;
if(myString == null || !int.TryParse(myString, out myInt))
{
myInt = 10;
}
Console.WriteLine(myInt);
}
#endregion
}
Je n'avais pas réalisé que ce dynamic
serait un facteur.
out
paramètre comme entréeout
paramètre. Il est certainement intéressant de considérer quel code d'assistance le compilateur devrait produire pour éviter le problème, ou si c'est même possible.Réponses:
Je suis presque sûr que c'est un bogue du compilateur. Bonne trouvaille!
Edit: ce n'est pas un bug, comme le démontre Quartermeister; dynamic pourrait implémenter un
true
opérateur étrange qui pourrait empêchery
l'initialisation.Voici un repro minimal:
Je ne vois aucune raison pour laquelle cela devrait être illégal; si vous remplacez dynamic par bool, il se compile très bien.
Je rencontre actuellement l'équipe C # demain; Je vais leur en parler. Toutes mes excuses pour l'erreur!
la source
d
peut être d'un type avec untrue
opérateur surchargé . J'ai posté une réponse avec un exemple où aucune branche n'est prise.Il est possible que la variable soit désassignée si la valeur de l'expression dynamique est d'un type avec un opérateur surchargé
true
.L'
||
opérateur invoquera l'true
opérateur pour décider s'il doit évaluer le côté droit, puis l'if
instruction invoquera l'true
opérateur pour décider s'il doit évaluer son corps. Pour un normalbool
, ceux-ci renverront toujours le même résultat et donc exactement un sera évalué, mais pour un opérateur défini par l'utilisateur, il n'y a pas une telle garantie!Sur la base de la repro d'Eric Lippert, voici un programme court et complet qui démontre un cas où aucun chemin ne serait exécuté et la variable aurait sa valeur initiale:
la source
d
être évalué deux fois? (Je ne conteste pas que clairement est , comme vous l' avez montré.) Je me serais attendu le résultat évalué detrue
( à partir de la première invocation de l' opérateur, cause en||
) être « passé le long de » laif
déclaration. C'est certainement ce qui se passerait si vous y mettiez un appel de fonction, par exemple.d
n'est évaluée qu'une seule fois, comme vous vous y attendez. C'est l'true
opérateur qui est appelé deux fois, une fois||
et une foisif
.var cond = d || M(out y); if (cond) { ... }
. Nous évaluonsd
d' abord pour obtenir uneEvilBool
référence d'objet. Pour évaluer le||
, nous appelons d'abordEvilBool.true
avec cette référence. Cela renvoie true, donc nous court-circuitons et n'invoquons pasM
, puis attribuons la référence àcond
. Ensuite, nous passons à laif
déclaration. L'if
instruction évalue sa condition en appelantEvilBool.true
.De MSDN (c'est moi qui souligne):
Étant donné que le compilateur ne contrôle ni ne résout aucune opération contenant des expressions de type dynamic, il ne peut garantir que la variable sera affectée via l'utilisation de
TryParse()
.la source
numberGroups
est affectée (dans leif true
bloc), sinon, la deuxième condition garantit l'affectation (viaout
).myString == null
(en se fondant uniquement sur leTryParse
).if
expression entière ) implique unedynamic
variable, elle n'est pas résolue au moment de la compilation (le compilateur ne peut donc pas faire ces hypothèses).