3

ほとんどの情報源によると、C# で ++ および -- 演算子をオーバーロードすると、接尾辞と接頭辞の両方が一度にオーバーロードされます。しかし、彼らの行動はまだ異なっているようです。

class Counter
{
    public Counter(int v = 0)
    {
        this.v = v;
    }
    public Counter(Counter c)
    {
        v = c.v;
    }
    public int GetValue() { return v; }
    public static Counter operator ++(Counter c)
    {
        c.v++;
        return new Counter(c);
    }
    private int v;
}


class Program
{
    public static void Main()
    {
        Counter c1 = new Counter(1);

        Counter c2 = c1++;

        Counter c3 = ++c1;

        c3++;

        System.Console.WriteLine("c1 = {0}", c1.GetValue());
        System.Console.WriteLine("c2 = {0}", c2.GetValue());
        System.Console.WriteLine("c3 = {0}", c3.GetValue());
    }
}

素晴らしいことに、この例では、オーバーロードoperator ++された元のクラスのコピーが返され、同じオブジェクトへの参照になり、別のオブジェクトを指します (ここ)。出力に変更します。c1c3c2c1=4, c2=2, c3=4Counter c3 = ++c1;Counter c3 = c1++;c1=3, c2=2, c3=4

では、接尾辞と接頭辞のインクリメント/デクリメントの正確な違いは何ですか?また、それがオーバーロードにどのように影響するのでしょうか? これらの演算子は、クラスとプリミティブ型に対して同じように機能しますか?

4

1 に答える 1

12

これは、C# でインクリメントとデクリメントを実装する間違った方法です。間違ったやり方をすると、おかしな結果になります。あなたはそれを間違っていました、あなたはクレイジーな結果を得たので、システムは機能します. :-)

偶然にも、私は先週まさにこのテーマについて記事を書きました:

http://ericlippert.com/2013/09/25/bug-guys-meets-math-from-scratch/

コメンターの dtb が指摘しているように、正しい実装は次のとおりです。

    public static Counter operator ++(Counter c)
    {
        return new Counter(c.v + 1);
    }

C# では、インクリメント演算子はその引数を変更してはなりません。むしろ、インクリメントされた値を計算して返すだけで、副作用は発生しません。変数を変更することの副作用は、コンパイラによって処理されます。

この正しい実装により、プログラムは次のようになります。

    Counter c1 = new Counter(1);

c1 が現在参照しているオブジェクトを呼び出しますWW.vは 1 です。

    Counter c2 = c1++;

これには次のセマンティクスがあります。

temp = c1
c1 = operator++(c1) // create object X, set X.v to 2
c2 = temp

したがって、c1今は を参照しX、 をc2参照しWます。 W.vは 1 とX.v2 です。

    Counter c3 = ++c1;

これには次のセマンティクスがあります。

temp = operator++(c1) // Create object Y, set Y.v to 3
c1 = temp
c3 = temp

したがって、c1 と c3 は両方とも object を参照しYY.v3 になります。

    c3++;

これには次のセマンティクスがあります。

c3 = operator++(c3) // Create object Z, set Z.v to 4

したがって、煙がすべて消えると、次のようになります。

c1.v = 3 (Y)
c2.v = 1 (W)
c3.v = 4 (Z)

そしてX孤児です。

c1これにより、通常の整数c2とまったく同じ結果が得られるはずです。c3

于 2013-10-02T15:49:49.290 に答える