質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

解決済

2回答

3821閲覧

getter、setter、プロパティについて

Akirana

総合スコア59

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

0クリップ

投稿2016/12/21 05:33

編集2016/12/21 06:20

ex1

class Person { public string name { get; set; } public int age { get; set; } }

ex2

class Person { public string name; public int age; }

ex3

class Person { private string mName; public int age; public string name { get { return mName; } set { mName = value; } }

ex1,ex2,ex3いずれも自身のクラス外から利用する場合、相違はありません。
私は多くの場合、ex2のパターンで実装をしています。

ex3.mNameの様に、クラス変数を隠蔽してプロパティを介して変数にアクセスをする意味はComputed Propertyとして利用する以外に意味はあるのでしょうか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

こんにちは。
下から回答していきます。

ex3の表記は、質問のコードのようにmNameをそのまま素通ししているなら、殆どの場合においてex1が完全上位互換になります。そもそもex1はex3のコードを自動生成するものなので。
上位互換にならない数少ない例外は、「getter/setterというメソッドを介さず、直接フィールド変数mNameにアクセスしなければならない場合」なのですが、この場面がどういうときかはちょっと思いつきません。もしあったとして、それはかなり黒魔術な空気がありますね……。

ex2については、少しばかりオブジェクト指向宗教論が入ってくるため、あまり主張しても仕方がない話ではあるのですが……自分なら、この設計は絶対に行いません。
理由としては、「Personクラスが自分のメンバーの値の状態を保証できなくなる」というものがあります。外から何か不正な値(例えば、年齢に負の値など)を設定されたとしても、それの責任をPersonクラスに持たせることができないのです。それをいうなら、ex1にも同様な責任問題がありますが、ex1の場合は「途中で仕様変更し、setterにValidation処理を挿入する(ex3に書き換える)」ことができます。ex2の場合はそれができません。そして、ex2からex1への変更は「破壊的変更になります」。よって、ex2のコードを書きたい場面では「何も考えずにex1のコードを書く」ことを推奨します。

最後にex1について。
POCOエンティティクラスなど、どうしてもその設計にせざるを得ない場合を除いて、setterを素のままpublicにするのは良くないです。前項で話した責任問題がその理由です。Validation処理をきっちり設定した上で公開するか、公開せずprivateなど内部に隠蔽するかの方法をとり、意図しない値変更を受ける可能性を可能な限り減らすことが大切になります。なので、ex1のコードのまま公開しなければならないとしたら、その時点でなにか設計がおかしいのではないかと疑うことができます。

結論としては、
フィールドは決して公開するべきではなく、必ずプロパティとして公開する。
ex2で書ける場面ではとりあえずex1のコードを書いておき、その上でなんとかsetterを隠蔽できないか、またはValidation処理を追加できないか、を考えるようにするのが良いと思います。

投稿2016/12/21 06:14

tamoto

総合スコア4252

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Akirana

2016/12/21 06:36

納得がいく内容です。 フィールドを公開するリスクについての思慮が欠けていました。 制限を強め、拡張性を保つため今後はex1のパターン+αで設計を行いたいと思います。 丁寧なご説明ありがとうございました。
guest

0

こんにちは。

C#の場合Stored PropertyComputed Propertyの区別はなくStored Propertyとしての役割(プロパティ監視)を実現する際にも有用です。

投稿2016/12/21 05:50

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Akirana

2016/12/21 06:39

ご回答ありがとうございます。 申し訳ございません。私の質問の仕方が悪かったです。 それぞれの実装による作用が知りたいと考えておりました。
Chironian

2016/12/21 06:55 編集

なるほど。 色々な意見があるのですが、最初はex2で実装しておき、必要が生じたらex3へ変更するのは妥当と思いますよ。 ex1が推奨されることは多いですが、ex1が有用な場面は少ないと思います。恐らく「プロパティ」の概念がない言語(Javaなど)でgetter/setterを常に用意することが推奨されますから、それをそのまま適用しているのだろうと思います。C#はプロバティもフィールドも外部からアクセスする構文は同じですから、フィールドを後でプロパティへ変更するリスクはないと思います。 プロパティのないJavaではそうは行かないので、最初からgetter/setterにしておくことが推奨されます。 getter/setterが推奨されるのは、クラスを拡張する際に内部データ構造を変更しやすいからなのです。他にgetter/setterにブレークを張ってデバックする際に有用と言う使い方もあります。(Stored Propertyの使い方ですね。) なお、外部への公開がリードオンリで十分な時はsetを実装しない、もしくは、setをprivateにするとアクセス制限できます。
tamoto

2016/12/21 07:12

横からコメント失礼します。 ex2からex3へ(フィールドからプロパティへ)の変更は破壊的になります。 フィールドの読み書きはメモリへの直接読み書き命令としてコンパイルされますが、プロパティはget/setメソッドの呼び出しとなります。 なので、publicなフィールド/プロパティを相互に書き換えてしまうと、それを参照する外部アセンブリが全て再コンパイルされないと実行時エラーを誘発するという状況になります。 以上の理由で、ex2を使いたい場面では使用感が同等であるex1を最初から使用することを推奨しています。 internal以下のaccesibilityであれば基本的にアセンブリ内で完結するので、その場合はフィールド/プロパティ間の書き換えは許容されます。
Chironian

2016/12/21 07:21

アセンブリ外部へ公開する時は変更できないのですか。それは知りませんでした。 訂正ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問