41 votes

Ne comprend pas le comportement de l'opérateur avant décrémentation avec le type Nullable

Ok, c'est peut-être évident pour certains d'entre vous mais je suis perplexe avec le comportement que je suis à partir de ce lieu un code simple:

public static void Main(string[] args)
{
    int? n = 1;
    int i = 1;
    n = ++n - --i;
    Console.WriteLine("Without Nullable<int> n = {0}", n); //outputs n = 2

    n = 1;
    i = 1;
    n = ++n - new Nullable<int>(--i);
    Console.WriteLine("With Nullable<int> n = {0}", n); //outputs n = 3
    Console.ReadKey();
}

Je exepcted les deux sorties à la même et égale à 2 mais, curieusement, ils ne le sont pas. Quelqu'un peut m'expliquer pourquoi?

EDIT: Bien que le code pour générer ce "bizarre" comportement n'est certes artificiel, il ne ressemble à un bug du compilateur C# mais apparemment sans importance et la raison semble être le inline new comme James l'a souligné au début. Mais le comportement n'est pas limitée aux opérations. Les appels de méthode se comportent exactement de la même manière, en ce qu'ils sont appelés à deux fois quand ils ne doit être appelé qu'une seule fois.

Considérez les points suivants repro:

public static void Main()
    {
        int? n = 1;
        int i = 1;
        n = n - new Nullable<int>(sideEffect(ref i));
        Console.WriteLine("With Nullable<int> n = {0}", n);
        Console.ReadKey();
    }

    private static int sideEffect(ref int i)
    {
        Console.WriteLine("sideEffect({0}) called", i);
        return --i;
    }

Bien sûr, la sortie est 2 alors qu'il devrait être 1 et "sideEffect(i) called" est imprimé deux fois.

20voto

thecoop Points 23695

EDIT: Cela a été confirmé comme un bogue dans le compilateur par l'équipe. Il est fixé dans Roslyn. Une solution consiste à utiliser un cast (int?)(--i) pour arrêter le bug apparaissant, ou ne sont pas explicitement exprimés à un Nullable<int> dans la première place.

Le premier bloc de code génère la suite de réflecteur:

int? nullable3;
int? nullable = 1;
int num = 1;
int? nullable2 = nullable;
nullable2 = nullable = nullable2.HasValue
    ? new int?(nullable2.GetValueOrDefault() + 1)    
   : ((int?) (nullable3 = null));
int num2 = --num;
nullable = nullable2.HasValue
    ? new int?(nullable2.GetValueOrDefault() - num2)
    : ((int?) (nullable3 = null));
Console.WriteLine("Without Nullable<int> n = {0}", nullable);

La deuxième suivantes:

nullable = 1;
num = 1;
nullable2 = nullable;
nullable2 = nullable = nullable2.HasValue
    ? new int?(nullable2.GetValueOrDefault() + 1)
    : ((int?) (nullable3 = null));
num2 = --num;
nullable = nullable2.HasValue
    ? new int?(nullable2.GetValueOrDefault() - --num)
    : null;
Console.WriteLine("With Nullable<int> n = {0}", nullable);

Ils sont plus ou moins les mêmes, jusqu'à la cession nullable. Il est de la course - --num deux fois, à l'origine pour exécuter 2 - -1, résultant en 3.

Il a également fait de même avec des expressions comme i = ~i, mais pas à l'appel de la méthode des expressions...

4voto

James Points 40024

C'est un problème intéressant, de ce que je peux voir le compilateur s'affiche pour évaluer l' --/++ des déclarations plus d'une fois. Par exemple, le suivant:

n = ++n - new Nullable<int>(i++)

résultats en n devenant 0 (qui vous attendent), mais i est désormais 3 (qui vous attendent à être 2). Toutefois, si je ne

n = ++n - new Nullable<int>(i);

Puis-je obtenir le résultat attendu (n = 1 et i = 1)

Je ne peux que supposer que c'est en quelque sorte lié à l' new Nullable d'achat en ligne. Je ne vois vraiment pas cela comme un problème, que ce ne serait probablement pas être considéré comme le quotidien de la sorte de code, cependant, à mon avis, il ne semble pas y avoir un bug avec le compilateur.

-2voto

Rene147 Points 1618

Eh bien, c’est le plus étrange, j’ai essayé de retrouver le code réel «-», mais j’en suis incapable mais si vous le faites

             n = 1;
        i = 1;
        n = ++n - new Nullable<int>(i--);
        Console.WriteLine("With Nullable<int> n = {0}", n); //outputs n = 2
        Console.ReadKey();
 

Il sort comme prévu.

edit: Tout est révélé:

http://msdn.microsoft.com/en-US/library/wc3z3k8c(v=vs.80).aspx

-3voto

Thomas Fonseca Points 240

C'est parce que sur cette ligne:

   n = ++n - new Nullable<int>(--i);
 

i devient -1 et 2 - (-1) = 3;

La raison pour laquelle il devient négatif 1 est que vous créez un objet nulluable initialisé à 0 puis en soustrayant un (i).

vous pouvez exécuter ce code en tant que fichier * .cshtml dans votre navigateur:

 @{

    int? m = 1;
    int i = 1;
    m = ++m - --i;
    //MessageBox.Show("Without Nullable<int> n = {0}", n); //outputs n = 2

    int? n = 1;
    i = 1;
    n = ++n - new Nullable<int>(--i);
    //MessageBox.Show("With Nullable<int> n = {0}", n); //outputs n = 3

}

<!DOCTYPE html>

<html lang="en">
<head>
    <meta charset="utf-8" />
    <title></title>
</head>
<body>
    <h2>m = @m</h2>
    <h2>n = @n</h2>
</body>
</html>
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X