自動実装プロパティを使用しています。フォローを修正する最も速い方法は、独自のバッキング変数を宣言することだと思いますか?
public Point Origin { get; set; }
Origin.X = 10; // fails with CS1612
エラーメッセージ:変数ではないため、「式」の戻り値を変更できません
中間式の結果である値型を変更しようとしました。値は永続化されないため、値は変更されません。
このエラーを解決するには、式の結果を中間値に保存するか、中間式に参照型を使用します。
これは、Point
が値型(struct
)であるためです。
このため、Origin
プロパティにアクセスするときは、参照型(class
)の場合のように値自体ではなく、クラスが保持している値のcopyにアクセスしているため、 X
プロパティを使用すると、コピーにプロパティを設定してから破棄し、元の値は変更されません。これはおそらくあなたが意図したものではないので、コンパイラはそれについて警告しています。
X
の値だけを変更する場合は、次のようにする必要があります。
Origin = new Point(10, Origin.Y);
バッキング変数を使用しても役に立ちません。 Point
タイプは値タイプです。
あなたは、Originプロパティにポイント値全体を割り当てる必要があります-
Origin = new Point(10, Origin.Y);
問題は、Originプロパティにアクセスすると、get
によって返されるものが、Originプロパティの自動作成フィールドのPoint構造のコピーであるということです。したがって、このコピーのXフィールドを変更しても、基になるフィールドには影響しません。この操作はまったく役に立たないため、コンパイラはこれを検出し、エラーを返します。
独自のバッキング変数を使用した場合でも、get
は次のようになります。
get { return myOrigin; }
それでも、Point構造体のコピーを返すことになり、同じエラーが発生します。
うーん...あなたの質問をもっと注意深く読んだので、おそらくあなたは実際にクラス内から直接バッキング変数を変更するつもりです:
myOrigin.X = 10;
はい、それはあなたが必要とするものです。
これで、エラーの原因をすでに把握できました。プロパティを取得するオーバーロードを持つコンストラクターが存在しない場合(この場合はX
)、オブジェクト初期化子を使用できます(これにより、背後ですべての魔法が実行されます)。 構造体を不変にする必要はないが、追加情報を与えるだけである:
struct Point
{
public int X { get; set; }
public int Y { get; set; }
}
class MyClass
{
public Point Origin { get; set; }
}
MyClass c = new MyClass();
c.Origin.X = 23; //fails.
//but you could do:
c.Origin = new Point { X = 23, Y = c.Origin.Y }; //though you are invoking default constructor
//instead of
c.Origin = new Point(23, c.Origin.Y); //in case there is no constructor like this.
これは、舞台裏でこれが起こるために可能です。
Point tmp = new Point();
tmp.X = 23;
tmp.Y = Origin.Y;
c.Origin = tmp;
これは非常に奇妙なことのように見えますが、まったくお勧めできません。別の方法をリストするだけです。より良い方法は、構造体を不変にし、適切なコンストラクターを提供することです
ここでの問題は、オブジェクト自体を割り当てるのではなく、ステートメントでオブジェクトのサブ値を割り当てようとしていることだと思います。この場合、プロパティタイプはPointであるため、Pointオブジェクト全体を割り当てる必要があります。
Point newOrigin = new Point(10, 10);
Origin = newOrigin;
私はそこに理にかなって願っています
問題は、スタックにある値をポイントすると、その値が元のプロパティに反映されないため、C#で値型への参照を返すことができないことです。 Originプロパティを削除し、代わりにパブリックフィールドを使用することでこれを解決できると思います。はい、それはニースのソリューションではないことがわかります。もう1つの解決策は、Pointを使用せず、代わりにオブジェクトとして独自のPointタイプを作成することです。
構造体とクラスの長所と短所を議論することは別として、私は目標を見て、その観点から問題にアプローチする傾向があります。
つまり、プロパティのgetおよびsetメソッドの背後にコードを記述する必要がない場合(例のように)、単にOrigin
をクラスのフィールドとして宣言するのは簡単ではありませんプロパティよりも?これで目標を達成できると思います。
struct Point
{
public int X { get; set; }
public int Y { get; set; }
}
class MyClass
{
public Point Origin;
}
MyClass c = new MyClass();
c.Origin.X = 23; // No error. Sets X just fine