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 …
ありがとうございます。
プロパティを使ったことではなく、フィールドをprivateにしたことによるエラーだったと行くことですか。
> privateなメンバを持つ構造体は、明示的なパラメータを持つコンストラクタを定義して初期化するか、new演算子に頼るかしない
納得しました。
配列の場合は、配列要素についても適切なコンストラクタが呼び出されるということのようですね。
No.2
- 回答日時:
C言語とは違い、原則として、C#はポインタを扱えない仕様にしています。
したがって構造体でも宣言だけでメモリーを確保するものではなく、実体化が必要なオブジェクト扱いになります。メソッドが加われば、間違いなくクラス扱いですから、逆に先のやり方ができる方が不自然な気がしました。結果オーライでいい加減ですが、new を使って実体化するように統一してコーディングしていけば、エラーは防げることでしょう。
もともとのプログラムに近づけると
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にアクセス制限をかけようとしてプロパーティに変更したところ、質問のような状況に陥ったというわけです。
No.1
- 回答日時:
解説を確認していないので、推測が多いので参考にならないかもしれませんが、ちょっと説明してみます。
最初のコードは構造体にセッタメソッドもゲッタメソッドもないので、純粋に構造体で、配列と同様にいきなり使えるのでしょう。
それに対して後のコードはセッタとゲッタを持つ構造体で、オブジェクトクラス扱いで準備されるのでしょう。したがっていったん名前を付けて実体化する手順を経なければ、後のSオブジェクトは抽象的オブジェクトのまま操作できないのでしょう。
ご回答くださり、ありがとうございます。
構造体オブジェクトは値型なので、メモリを確保しただけで使えるものと理解していました。
Sが構造体型のとき、
S z = new S();
は、オブジェクトの実体を作るという意味ではなく、オブジェクトを作って、それを変数zにコピーすることによって変数のメモリ領域を初期化するということではありませんか。
変数の宣言
S z;
と配列の確保(質問中の記載は誤っていました)
S[] x = new S[10];
を較べたとき、前者で初期化がおこなわれないのであれば、後者は10個の配列要素の記憶場所を確保しているけれども、それぞれの配列要素は初期化がなされていないことになり、配列要素を参照してもエラーにならないのが腑に落ちなかったわけです。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Java javaでのプログラム(配列)について質問です. 2 2022/10/14 22:27
- Java java 入力 3 4 3 出力 ABC DEFG HIJ このようなプログラムの書き方を教えてくだ 2 2022/07/15 14:18
- Java Java プログラム public class Main { public static void 3 2023/08/10 23:46
- C言語・C++・C# C言語初心者 構造体 課題について 2 2023/03/10 19:48
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
- Java 直し方について教えて頂きたいです。 4 2022/08/13 02:11
- C言語・C++・C# C言語初心者 構造体 課題について 1 2023/03/10 19:30
- C言語・C++・C# C言語のエラーについて 2 2022/07/11 13:56
- Ruby 【JAVA】数字をひし形に出力するプログラムについて 2 2022/07/11 23:32
- C言語・C++・C# C# DatagridviewにExcelシートを反映するとエラーが出る 2 2023/05/06 17:12
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
実行時エラー 438になった時の...
-
エクセルエラー13型が一致しま...
-
実行時エラー3001「引数が間違...
-
ExcelVBA Range クラスの Page...
-
なぜこんな初歩的なVBAのIf文で...
-
ACCESSのエラーで困っています
-
VBAがブレークモードになっ...
-
Application.ActiveInspectorで...
-
職場から目的地までの距離集計
-
VBS実行時エラー オブジェクト...
-
DataGridView からの値取得に関...
-
Excel2019 ワークシートのコピ...
-
VB6+SQL サーバー 2000 で 実行...
-
Outlook.ApplicationをCreateOb...
-
VBAでのエラー
-
ASP.NET OleDbConnectionが定義...
-
Access マクロでのテーブル削除
-
一般ODBCエラーについて
-
日本語環境下で作成したマクロ...
-
【Excel VBA】マクロをボタンに...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
実行時エラー 438になった時の...
-
エクセルエラー13型が一致しま...
-
【Excel VBA】マクロをボタンに...
-
VBAでのエラー
-
マクロについて教えてください...
-
なぜこんな初歩的なVBAのIf文で...
-
VBAがブレークモードになっ...
-
実行時エラー3001「引数が間違...
-
ExcelVBA Range クラスの Page...
-
VBS実行時エラー オブジェクト...
-
EXCEL VBAマクロ中断でデバッグ...
-
Outlook.ApplicationをCreateOb...
-
VBSで変数の宣言はできないので...
-
VBAのコードがエラーになっ...
-
実行時エラー -'-2147417848
-
ADODB.Streamを使用してUTF-8を...
-
EXCEL/VBAで、自分のPCだけエラ...
-
OLEDB.NETで接続できない
-
プロシージャ名の取得
-
VB6+SQL サーバー 2000 で 実行...
おすすめ情報