こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

C#でプロパティをもつ構造体型の変数を使う

C#のプログラム
struct S
{
public int A;
}
class Program
{
static void Main(string[] args)
{
S z;
z.A = 0;
}
}
には文法エラーはありません。
ところが、構造体の定義を
struct S
{
private int a;
public int A
{
set { a = value; }
get { return a; }
}
}
に変えると、Mainメソッドの
z.A = 0;
の行で
「未割り当てのローカル変数 'z' が使用されました。」
のエラーが出ます。
その上の行を
S z = new S();
に変えれば、このエラーはなくなります。
このエラーはどうして出るのでしょうか。

なお、
S[] x = new x[10];
のように、構造体の配列にすると、(配列要素には値が割り当てられてはいないのに、)
x[0].A = 1;
としてもエラーは出ません。

投稿日時 - 2011-02-03 11:48:05

QNo.6494657

暇なときに回答ください

質問者が選んだベストアンサー

どうも、この質問が気になって、ちょっと調べてみたのですが、参考URLの中の、

>各フィールドは未割り当てのままになり、すべてのフィールドが初期化されるまではオブジェクトを使用できません。
というのと、
>構造体は new 演算子を使用せずにインスタンス化できます。このような場合、コンストラクタの呼び出しが行われないため、

を考え合わせると、z.aを明示的に初期化しない為にエラーが出ているのではないでしょうか?(エラーのメッセージに不満は残りますが)
試しに、aをpublicにして、
S z;
z.a=0;
とすると、エラーは出ません。

new演算子を使用すると、適切なコンストラクタが呼び出される、と書かれており、それによって、メンバは初期化されるようです。逆に言うと、privateなメンバを持つ構造体は、明示的なパラメータを持つコンストラクタを定義して初期化するか、new演算子に頼るかしないと、使えない、ということになりますね。
ちなみに、構造体は宣言だけで実体は作られます。値型ですから。

参考URL:http://msdn.microsoft.com/ja-jp/library/0taef578%28v=VS.90%29.aspx

投稿日時 - 2011-02-13 06:06:17

お礼

 ありがとうございます。
プロパティを使ったことではなく、フィールドをprivateにしたことによるエラーだったと行くことですか。
> privateなメンバを持つ構造体は、明示的なパラメータを持つコンストラクタを定義して初期化するか、new演算子に頼るかしない
 納得しました。

 配列の場合は、配列要素についても適切なコンストラクタが呼び出されるということのようですね。

投稿日時 - 2011-02-13 12:39:22

このQ&Aは役に立ちましたか?

1人が「このQ&Aが役に立った」と投票しています

回答(3)

ANo.2

C言語とは違い、原則として、C#はポインタを扱えない仕様にしています。したがって構造体でも宣言だけでメモリーを確保するものではなく、実体化が必要なオブジェクト扱いになります。メソッドが加われば、間違いなくクラス扱いですから、逆に先のやり方ができる方が不自然な気がしました。
結果オーライでいい加減ですが、new を使って実体化するように統一してコーディングしていけば、エラーは防げることでしょう。

投稿日時 - 2011-02-12 16:09:27

お礼

もともとのプログラムに近づけると
struct S : System.IComparable<S>
{
public int A, B;
public int CompareTo(S z)
{
int compare=A.CompareTo(z.A);
return (compare != 0) ? compare : B.CompareTo(z.B);
}
}
class Program
{
static void Main(string[] args)
{
S x, y;
x.A = 1; x.B = 2;
y.A = 3; y.B = 4;
Console.WriteLine(x.CompareTo(y));
}
}
で、構造体Sにはpublicなメソッドがありました。このフィールドAとBにアクセス制限をかけようとしてプロパーティに変更したところ、質問のような状況に陥ったというわけです。

投稿日時 - 2011-02-12 22:33:11

ANo.1

 解説を確認していないので、推測が多いので参考にならないかもしれませんが、ちょっと説明してみます。
 最初のコードは構造体にセッタメソッドもゲッタメソッドもないので、純粋に構造体で、配列と同様にいきなり使えるのでしょう。
 それに対して後のコードはセッタとゲッタを持つ構造体で、オブジェクトクラス扱いで準備されるのでしょう。したがっていったん名前を付けて実体化する手順を経なければ、後のSオブジェクトは抽象的オブジェクトのまま操作できないのでしょう。

投稿日時 - 2011-02-05 01:05:15

お礼

ご回答くださり、ありがとうございます。
構造体オブジェクトは値型なので、メモリを確保しただけで使えるものと理解していました。
Sが構造体型のとき、
S z = new S();
は、オブジェクトの実体を作るという意味ではなく、オブジェクトを作って、それを変数zにコピーすることによって変数のメモリ領域を初期化するということではありませんか。
変数の宣言
S z;
と配列の確保(質問中の記載は誤っていました)
S[] x = new S[10];
を較べたとき、前者で初期化がおこなわれないのであれば、後者は10個の配列要素の記憶場所を確保しているけれども、それぞれの配列要素は初期化がなされていないことになり、配列要素を参照してもエラーにならないのが腑に落ちなかったわけです。

投稿日時 - 2011-02-09 13:02:12

あなたにオススメの質問