トップ回答者
クラスか構造体かの選択

質問
-
あけましておめでとうございます。本年もよろしくお願いいたします。<(_ _)>
さて現在 .NET のクラスライブラリ設計 を読み進めている訳ですが、幾つか引っかかる箇所があります。
まず 71頁にDO NOT (してはいけない) として以下の性質をすべて満たす型でない限り、構造体を定義してはいけません。
・プリミティブ型(int、doubleなど)のように、論理的に単一の型を表現する
・インスタンスの型が16バイト未満である
・・・以下略とあります。
その下のコラムで Jeffrey が「インスタンスが、すべてボックス化されている必要があるコレクションに配置されるならば、値型を定義することは推奨されません。しかしながら、幸いにも、新しいCLR、C#、およびその他の言語はジェネリックをサポートするので、コレクションに値型のインスタンスを投入するときのボックス化はもはや必要ありません。」
と書いております。
これを読む限り、ジェネリック型のコレクションでは構造体のボックス化は発生しないと思われるのですが、その解釈で誤りはないでしょうか?
また、String をメンバに持ち、かつ住所等のデータを保持する構造体は、必然的に 16バイトを超える訳ですが、
これを DO NOT というのはどうかと思うのですが、いかがでしょうか?
# っていうか、そもそも16バイトの根拠って何?とか思っちゃう訳ですが・・・
回答
-
これを読む限り、ジェネリック型のコレクションでは構造体のボックス化は発生しないと思われるのですが、その解釈で誤りはないでしょうか?
はい、その通りです。でもそれは先にお挙げになった項目と別に矛盾しないと思います。それ以外の項目と関係があるのかも知れませんけど。
ちなみにこれは基本的にクラスライブラリ設計の話であり、その型の使用者がその型をどう使うかは判断しきれない部分があるための汎用的な判断基準であると考えられます。また、String をメンバに持ち、かつ住所等のデータを保持する構造体は、必然的に 16バイトを超える訳ですが、
そもそもそんなのを値型にするべきとも思わないので、どうでもいいですね。
これを DO NOT というのはどうかと思うのですが、いかがでしょうか?# っていうか、そもそも16バイトの根拠って何?とか思っちゃう訳ですが・・・
推測ですが、値のコピーと参照のコピーのコストからでしょう。- 回答としてマーク ひらぽんModerator 2010年1月5日 2:45
-
> これはイマイチ頭に入ってこない
struct A { }
昔
ArrayList list = new ArrayList();
list.Add(new A());
list.Add(new A());
list.Add(new A());
// すべてボックス化されて保存され、取り出すときにアンボックス化される
今
List<A> list = new List<A>();
list.Add(new A());
list.Add(new A());
list.Add(new A());
// ジェネリックスによってボックス化されずに保存される
という違いを踏まえて、
前者のような、常にボックス化されて保存されるような使い方しかしないなら、
あえて、クラス型で作成しておくことで、ボックス化のコストを抑えることができる。
(=値型は推奨されない)
と、いいたいのではないかと。- 回答としてマーク ひらぽんModerator 2010年1月5日 2:45
すべての返信
-
これを読む限り、ジェネリック型のコレクションでは構造体のボックス化は発生しないと思われるのですが、その解釈で誤りはないでしょうか?
はい、その通りです。でもそれは先にお挙げになった項目と別に矛盾しないと思います。それ以外の項目と関係があるのかも知れませんけど。
ちなみにこれは基本的にクラスライブラリ設計の話であり、その型の使用者がその型をどう使うかは判断しきれない部分があるための汎用的な判断基準であると考えられます。また、String をメンバに持ち、かつ住所等のデータを保持する構造体は、必然的に 16バイトを超える訳ですが、
そもそもそんなのを値型にするべきとも思わないので、どうでもいいですね。
これを DO NOT というのはどうかと思うのですが、いかがでしょうか?# っていうか、そもそも16バイトの根拠って何?とか思っちゃう訳ですが・・・
推測ですが、値のコピーと参照のコピーのコストからでしょう。- 回答としてマーク ひらぽんModerator 2010年1月5日 2:45
-
愚問にお付き合い頂きまことにありがとうございます。<(_ _)>
> そもそもそんなのを値型にするべきとも思わないので、どうでもいいですね。
今まで深く考えたことがなかったのですが、改めて Int32 や Double、String のドキュメントを見直してみました。
Int32 や Double は構造体、String はクラスだったんですよね。(^ω^;
いや、知ってたつもりなんですが・・・改めて意識すると、確かに構造体にクラスをメンバに加えるのはどうよと思いました(大汗
> 推測ですが、値のコピーと参照のコピーのコストからでしょう。
なるほど・・・そう言われてみると納得です。「インスタンスが、すべてボックス化されている必要があるコレクションに配置されるならば、値型を定義することは推奨されません。しかしながら、幸いにも、新しいCLR、C#、およびその他の言語はジェネリックをサポートするので、コレクションに値型のインスタンスを投入するときのボックス化はもはや必要ありません。」
> ちなみにこれは基本的にクラスライブラリ設計の話であり、その型の使用者がその型をどう使うかは判断しきれない部分があるための汎用的な判断基準であると考えられます。
これはイマイチ頭に入ってこない・・・自分の脳みそのキャパを恨むばかりです。(-ω-;
一応他の方の意見も聞いてみたいので、一週間ばかり閉じないでおきます。御了承の程を。<(_ _)> -
> これはイマイチ頭に入ってこない
struct A { }
昔
ArrayList list = new ArrayList();
list.Add(new A());
list.Add(new A());
list.Add(new A());
// すべてボックス化されて保存され、取り出すときにアンボックス化される
今
List<A> list = new List<A>();
list.Add(new A());
list.Add(new A());
list.Add(new A());
// ジェネリックスによってボックス化されずに保存される
という違いを踏まえて、
前者のような、常にボックス化されて保存されるような使い方しかしないなら、
あえて、クラス型で作成しておくことで、ボックス化のコストを抑えることができる。
(=値型は推奨されない)
と、いいたいのではないかと。- 回答としてマーク ひらぽんModerator 2010年1月5日 2:45
-
> これはイマイチ頭に入ってこない
struct A { }
昔
ArrayList list = new ArrayList();
list.Add(new A());
list.Add(new A());
list.Add(new A());
// すべてボックス化されて保存され、取り出すときにアンボックス化される
今
List<A> list = new List<A>();
list.Add(new A());
list.Add(new A());
list.Add(new A());
// ジェネリックスによってボックス化されずに保存される
という違いを踏まえて、
前者のような、常にボックス化されて保存されるような使い方しかしないなら、
あえて、クラス型で作成しておくことで、ボックス化のコストを抑えることができる。
(=値型は推奨されない)
と、いいたいのではないかと。
新年早々回答頂きありがとうございます。やっと理解できました。
具体例をあげて頂いたおかげで、すっきり頭に入ってきました。<(_ _)>
#しかし、私の頭が悪いのか、翻訳が微妙なのか、それとも両方なのか・・・(-ω-; -
とりあえず自分の中では解決してますが、今後の参考までに追記しておきます。
その後、いろいろ調べていたら下記の記事が見つかりました。
構造体とクラスの選択 - @IT Insider.NET 会議室
http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=46521&forum=7&start=0構造体とクラスの使い分け
http://d.hatena.ne.jp/NyaRuRu/20080930/p2.NET のクラスライブラリ設計 を読みこなすには CLR の深い話も知らないとだめだと思い、
荒井さんの The Root of .NET Framework も合わせて読んでいるのですが、
この辺の話も絡めて考えると、かなり参考になりますね。