Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
144 views
in Technique[技术] by (71.8m points)

c# - Don't understand pre decrement operator behavior with Nullable type

Ok, this might be obvious for some of you but I am stumped with the behavior I'm getting from this rather simple code:

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();
}

I exepcted both outputs to be the same and equal to 2 but strangely enough they aren't. Can someone explain why?

EDIT: Although the code to generate this "weird" behavior is admittedly contrived, it does look like a bug in the C# compiler though seemingly unimportant and the reason seems to be the inlined new as James pointed out initially. But the behavior is not limited to operations. Method calls behave exactly the same way, that is, they are called twice when they should only be called once.

Consider the following 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;
    }

Sure enough, output is 2 when it should be 1 and "sideEffect(i) called" is printed out twice.

question from:https://stackoverflow.com/questions/16818963/dont-understand-pre-decrement-operator-behavior-with-nullable-type

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

EDIT: This has been confirmed as a bug in the compiler by the team. It is fixed in Roslyn. As a workaround, use a cast (int?)(--i) to stop the bug appearing, or don't explicitly cast it to a Nullable<int> in the first place.

The first code block generates the following in reflector:

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);

The second the following:

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);

They're more or less the same, up to the assignment to nullable. It's running --num twice, causing it to run 2 - -1, resulting in 3.

It also does the same with expressions like i = ~i, but not with method call expressions...


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...