4

わかりました、私は変更可能な構造体の背後にある悪を理解していると言って質問を始めますが、私は SFML.net で作業しており、Vector2f やそのような構造体をたくさん使用しています。

私が理解していないのは、クラス内のフィールドを持つことができ、その値を変更でき、まったく同じクラス内のプロパティで同じことを行うことができない理由です。

このコードを見てください:

using System;

namespace Test
{
    public struct TestStruct
    {
        public string Value;
    }

    class Program
    {
        TestStruct structA;
        TestStruct structB { get; set; }

        static void Main(string[] args)
        {
            Program program = new Program();

            // This Works
            program.structA.Value = "Test A";

            // This fails with the following error:
            // Cannot modify the return value of 'Test.Program.structB'
            // because it is not a variable
            //program.structB.Value = "Test B"; 

            TestStruct copy = program.structB;
            copy.Value = "Test B";

            Console.WriteLine(program.structA.Value); // "Test A"
            Console.WriteLine(program.structB.Value); // Empty, as expected
        }
    }
}

注:同じ機能をカバーし、可変性を維持するために独自のクラスを構築しますが、一方を実行できて他方を実行できない技術的な理由がわかりません。

4

2 に答える 2

12

フィールドにアクセスするときは、実際の構造体にアクセスしています。プロパティを介してアクセスする場合は、プロパティに格納されているものをすべて返すメソッドを呼び出します。値型である構造体の場合、構造体のコピーが返されます。どうやらそのコピーは変数ではなく、変更できません。

C# 言語仕様 5.0 のセクション「1.7 構造体」には、次のように記載されています。

クラスでは、2 つの変数が同じオブジェクトを参照する可能性があるため、1 つの変数に対する操作が、他の変数によって参照されるオブジェクトに影響を与える可能性があります。構造体では、変数はそれぞれ独自のデータのコピーを持ち、一方の操作が他方に影響を与えることはできません。

これは、構造体のコピーを受け取り、元の構造体を変更できないことを説明しています。ただし、許可されない理由については説明されていません。

仕様のセクション「11.3.3」:

構造体のプロパティまたはインデクサーが割り当てのターゲットである場合、プロパティまたはインデクサー アクセスに関連付けられているインスタンス式は、変数として分類する必要があります。インスタンス式が値として分類される場合、コンパイル時エラーが発生します。これについては、§7.17.1 でさらに詳しく説明します。

したがって、get アクセサーから返される「もの」は値であり、変数ではありません。これは、エラーメッセージの文言を説明しています。

仕様には、コードとほぼ同じセクション 7.17.1 の例も含まれています。

宣言を考えると:

struct Point
{
    int x, y;
    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
    public int X {
        get { return x; }
        set { x = value; }
    }
    public int Y {
        get { return y; }
        set { y = value; }
    }
}
struct Rectangle
{
    Point a, b;
    public Rectangle(Point a, Point b) {
        this.a = a;
        this.b = b;
    }
    public Point A {
        get { return a; }
        set { a = value; }
    }
    public Point B {
        get { return b; }
        set { b = value; }
    }
}

例では

Point p = new Point();
p.X = 100;
p.Y = 100;
Rectangle r = new Rectangle();
r.A = new Point(10, 10);
r.B = p;

p と r は変数であるため、pX、pY、rA、および rB への代入は許可されます。ただし、例では

Rectangle r = new Rectangle();
r.A.X = 10;
r.A.Y = 10;
r.B.X = 100;
r.B.Y = 100;

rA と rB は変数ではないため、代入はすべて無効です。

于 2013-08-17T18:39:19.283 に答える