41

わかりました、これは一部の人にとっては明らかかもしれませんが、私はこのかなり単純なコードから得ている動作に困惑しています:

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

両方の出力が同じで等しいと期待しました2が、奇妙なことに、そうではありません。誰かが理由を説明できますか?

編集:この「奇妙な」動作を生成するコードは確かに不自然ですが、一見重要ではないように見えますが、C# コンパイラのバグのように見えます。その理由は、James が最初に指摘したようにインライン化newされいるようです。しかし、動作は操作に限定されません。メソッド呼び出しはまったく同じように動作します。つまり、1 回だけ呼び出されるはずのメソッドが 2 回呼び出されます。

次の再現を検討してください。

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

案の定、出力は本来2あるべきタイミングであり1"sideEffect(i) called"2 回出力されます。

4

4 に答える 4

20

編集:これは、チームによってコンパイラのバグとして確認されています。これは Roslyn で修正されています。回避策として、キャスト(int?)(--i)を使用してバグが表示されないようにするかNullable<int>、最初から明示的にキャストしないでください。

最初のコード ブロックは、リフレクターで次を生成します。

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

2番目は次のとおりです。

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

への割り当てまで、それらは多かれ少なかれ同じですnullable--num2回実行されているため、実行2 - -1され、結果は3になります。

のような式でも同じことi = ~iができますが、メソッド呼び出し式ではそうではありません...

于 2013-05-29T16:34:09.887 に答える
4

これは非常に興味深い問題です。私が見る限り、コンパイラは/ステートメントを複数回評価しているように見えます。たとえば、次のようになります。--++

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

nなる0(予想される) が、i現在3(になると予想される2) になります。しかし、もしそうなら

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

次に、期待される結果を取得します ( n=1およびi= 1)

これは、コールがインラインであることに何らかの形で関連しているとしか思えません。new Nullableこれはおそらく日常的なコードとは見なされないため、これが大きな問題になるとは思いませんが、私の意見では、コンパイラのバグのようです。

于 2013-05-29T16:30:34.567 に答える
-2

最も奇妙なことに、「--」から実際のコードを突き止めようとしましたが、できません。

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

期待どおりに出力されます。

編集:すべてが明らかにされています:

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

于 2013-05-29T16:36:19.170 に答える
-3

これは、次の行にあるためです。

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

i は -1 と 2 - (-1) = 3 になります。

負の 1 になる理由は、0 に初期化された null 可能なオブジェクトを新しく作成してから、1 (i) を減算しているためです。

このコードをブラウザーで *.cshtml ファイルとして実行できます。

@{

    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>
于 2013-05-29T16:48:19.663 に答える