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

このQ&Aのポイント
  • C#のプログラムで、プロパティを持つ構造体型の変数を使う際、文法エラーが発生する場合があります。
  • 特に、構造体の定義を変更し、プロパティにセッターとゲッターを追加すると、変数の使用に関するエラーが発生することがあります。
  • また、構造体の配列に値を割り当てずに要素にアクセスする場合、エラーは発生しません。
回答を見る
  • ベストアンサー

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; としてもエラーは出ません。

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

  • ベストアンサー
回答No.3

どうも、この質問が気になって、ちょっと調べてみたのですが、参考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
akayoroshi
質問者

お礼

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

その他の回答 (2)

  • seastar3
  • ベストアンサー率69% (99/142)
回答No.2

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

akayoroshi
質問者

お礼

もともとのプログラムに近づけると 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にアクセス制限をかけようとしてプロパーティに変更したところ、質問のような状況に陥ったというわけです。

  • seastar3
  • ベストアンサー率69% (99/142)
回答No.1

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

akayoroshi
質問者

お礼

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

関連するQ&A

  • C#の構造体に関して

    C#の構造体に関して C#で構造体で配列を持ちたいと思い、宣言の仕方や使い方を 勉強していますが、どうしてもコンパイルは通るもののエラーと なってしまいます。 《ソース》 単純に構造体で宣言した"a"という配列に、"ABC"という文字列を 代入したいだけですが。。。 namespace テスト環境 { struct test { public string []a; } class Program { static void Main(string[] args) { test aaa = new test(); aaa.a[0] = "ABC"; } } } 配列の初期化等は、ようやく理解したつもりではいますが、構造体 が絡むとどうしてもわかりません。 どこをどのように修正したら良いかを教えて下さい。 初歩的な質問で申し訳ありませんが、よろしくお願いします。

  • 構造体の配列を関数に渡すには

    構造体の配列を関数の引数として渡そうとすると エラーになってしまいます ネットで調べてもいまいちわからなかったので ここで質問させてもらいます #include<stdio.h> struct A{   ・    ・    ・ }; void func(struct A *p); int main(void) { struct A x[3][4] = {     ・     ・     ・ }; func(x); return 0; } void func(struct A *p){     ・     ・    ・ } どうすれば渡すことができるのでしょうか? どなたか助言お願いします。

  • 構造体の初期設定 (C++)

    構造体の初期設定 (C++) C++言語にて以下のコードをコンパイルすると9行目でERROR(E2188 構文エラー)がでます。 【質問】  9行目をどう直せばいいのでしょうか。 -------------------------------------- struct strData{ int a; int *b; }; void main(void) { struct strData *strc; *strc = {5,(int*)6}; /* 9行目 */ } -------------------------------------- 参考書やネットで調べたのですが解説が見つかりませんでしたので。。

  • .NET C++で、構造体の配列をnewで作成しようとするとerror C2440のエラーとなってしまいます

    Visual studio2003 .NET C++で、構造体の配列を作成し、 改めて構造体の配列をサイズ指定して作成しようとすると、error C2440が出てしまいます。 ポインターで宣言したつもりはないのですが、ポインターから配列に変換できないといった項目のエラーなので、 なぜこのようなエラーが出るのかわからずにおります。 typedef __nogc struct TEST { // 省略 }; TEST struct_test __nogc[]; int int_num = 10; struct_test = new TEST __nogc[int_num]; // error C2440: '=' : 'TEST *' から 'TEST []' に変換できません。 ご指摘等ありましたらご回答いただけますと助かります。 よろしくお願いいたします。

  • ポインタを使った構造体のプログラム

    ポインタを使ってメンバに値を入力して表示するプログラムを作ったのですが、mainのstruct XYZ aというオブジェクトと*bというそれを指すポインタを使ってプログラムを表示するにはどうすればいいのでしょうか。 これがプログラムです。 #include <stdio.h> struct XYZ { int x; long int y; double z; }; void set_xyz(struct XYZ *p,int x,long int y,double z) { p->x=x; p->y=y; p->z=z; } //void set_xyz(struct XYZ *,int,long int,double); int main() { struct XYZ a = {12,999999,1.41421356},*b; //ここのポインタ変数bでエラーが表示されます。 set_xyz(b,a.x,a.y,a.z); printf("a.x = %d\na.y = %d\na.z = %lf\n",b->x,b->y,b->z); return 0; } エラーの内容は「初期化されていないローカル変数 'b' が使用されます」となっています。 初歩的な質問ですみません・・・。

  • C言語 構造体配列について

    6人分の小テストの点数を記録し,平均値などを計算するプログラムを作成している. 以下の手順と条件に従ってプログラムを作成. 手順 (1) 氏名(name[100], char 型) と点数( score , int 型) をメンバにもつ構造体「struct_TEST」を(main 関数の外で)定義. (2) struct _TEST 型構造体配列 element[6] を定義. (3) キーボードから氏名(ローマ字でよい)と点数を入力する処理を6 回繰り返す. (4) 平均点を計算して画面表示. (5) 最高点を出した人の名前と点数を画面表示. (6) 平均点に満たない人の名前と点数を画面表示. 条件 (3)~(6)の処理には以下に示す関数を利用する. (3) ・・・ 氏名と点数を入力する処理をn 回繰り返す関数 void input_score( struct _TEST *a, int n ) (4) ・・・ n 個の構造体配列に対して平均を計算し,平均点を返す関数 double calc_ave( struct _TEST *a, int n ) (5) ・・・ n 個の構造体配列に対して最高点を算出し,そのユーザの配列番号を返す関数 int calc_max( struct _TEST *a, int n ) (6) ・・・ n 個の構造体配列に対して平均点に満たない人の名前と点数を画面表示する関数 void show_under_ave( struct _TEST *a, int n ) C言語の構造体が良く分かっていません。 こういった条件が多いと考えづらく分からなくなります。 考えても分かっていないので困っています。 誰かすみませんが解答を教えて下さい。

  • C言語構造体についてです。

    C言語、π=PI 3.14159265で構造体を用いてmensekiを呼び出して 半径と面積を計算して出力するプログラムです。下の空白を埋めてもらえますか? /* 構造体のプログラム */ #include <stdio.h> #include <math.h> #define PI 3.14159265 struct Data { /* 半径rと面積areaをdoubleで宣言 */ }; void menseki(struct ... 構造体のポインタを引数とする ){ /* 面積を計算する際に構造体のアドレスから計算する */ circle->area=PI* .....; } main(){ struct Data example[2]; //構造体配列 int i; /* 半径rを構造体配列を用いて2例入力する */ /* 2例の各々について mensekiを呼び出して 半径と面積を計算して出力する */ } よろしくお願いします。

  • C言語の構造体についてなんですが。

    struct LIST {     struct Num* number;     struct LIST* next;/* 次の要素へのポインタ */ }*root; struct Num{     int a;     struct Num* next; /* 次の要素へのポインタ */ }*numroot; と構造体を定義したときに、 main(){     struct LIST *p;     for(p = root; p != NULL; p = p->next) ; } とすれば、pの先頭からNULLまでを参照していくことは分かるんですが、pのnumberの先頭からNULLまでの参照方法(プログラムのfor文の記述方法)がイマイチわかりません。つまり、構造体の構造体をどのように参照するかということです。 これを実現したい理由は、構造体内での数の格納を配列(固定長)ではなく可変長で格納したいからです。 分かる方は解答をお願いします。

  • C言語 構造体に関するプログラムのエラーについて

    次は自分で書いたプログラムの一部なのですが、このプログラムをコンパイルすると以下のようなエラーが表示されます。 struct monster{ int type; /* タイプ */ char trick[25]; /* 技 */ char trick2[25]; /* 技2 */ int tricktype; /* 技1のタイプ */ int tricktype2; /* 技2のタイプ */ int trickeffect; /* 技1の威力 */ int trickeffect2; /* 技2の威力 */ char name[10]; /* 名前 */ int power; /* 攻撃力 */ int diffence; /* 防御力 */ int speed; /* 素早さ */ int HP; /* 体力 */ /* 1,fire 2,water 3,nature 4,thunder 5,wind */ }; struct monster monster2[5] = { { 1, "a", "b", 1, 2, 120, 80, "v", 60, 60, 60, 100}, { 2, "a", "b", 2, 3, 120, 80, "w", 60, 60, 60, 100}, { 3, "a", "b", 3, 4, 120, 80, "x", 60, 60, 60, 100}, { 4, "a", "b", 4, 5, 120, 80, "y", 60, 60, 60, 100}, { 5, "a", "b", 5, 1, 120, 80, "z", 60, 60, 60, 100}, } void battle(int a[2][3], struct monster monster[], struct monster monster2[]) { ・ ・ ・ printf("player2は%sをくりだした。\n", monster2.name[a[1][0] - 1]); ・ ・ printf("%sの残り体力は%d。\n", monster2.name[a[1][0] - 1], monster2.HP[a[1][0] - 1]); } monsterbattle.c:467:61: エラー: 構造体または共用体ではない何かのメンバ ‘name’ の 要求です printf("player2は%sをくりだした。\n", monster2.name[a[1][0] - 1]); ^ monsterbattle.c:475:52: エラー: 構造体または共用体ではない何かのメンバ ‘name’ の 要求です printf("%sの残り体力は%d。\n", monster2.name[a[1][0] - 1], monster2.HP[a[1 ][0] - 1]); ^ monsterbattle.c:475:80: エラー: 構造体または共用体ではない何かのメンバ ‘HP’ の要 求です printf("%sの残り体力は%d。\n", monster2.name[a[1][0] - 1], monster2.HP[a[1 ][0] - 1]); このようなエラーがあちこちで表示されるのですが、どのようにプログラミングを改善すべきなのでしょうか? お手数ですが、よろしくお願いします。

  • データ数の多い構造体配列

    メンバが配列である構造体配列を定義したいのですが、 struct hei { double *hight=(double*)malloc(sizeof(double) * 2*max + 1); }; int main() { struct hei h[10]; : : : という風にはできないのでしょうか。 「構文エラー : ';' が '=' の前にありません」とエラーが出てしまいます。

専門家に質問してみよう