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

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

ただいまの
回答率

89.72%

C# 同クラスでは直接代入、他クラスではSetterの理由

解決済

回答 7

投稿

  • 評価
  • クリップ 0
  • VIEW 1,659

madakko

score 8

お世話になります。
C#のコードの書き方について質問です。

以下のような、privateフィールドと、単純なアクセサが設定されたコードがあり、

private bool flag = false;
public bool GetFlag(){ return flag; }
public void SetFlag(bool value){ flag = value; }

同クラス内では flag = true のような直接代入、
他クラスでは SetFlag(true) のようなアクセサで代入となっていました。

個人的にはアクセサに統一したほうが、メンテナンスしやすいと考えるのですが、このように分けて書く理由を教えたいただければ幸いです。
私としては、処理が早くなるくらいしか思いつかず。。。

どうぞよろしくお願いいたします。

【補足】
C++からの移植コードのため、プロパティとして定義されていません。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 7

checkベストアンサー

+2

こんにちは。

個人的にはアクセサに統一したほうが、メンテナンスしやすいと考えるのですが、このように分けて書く理由を教えたいただければ幸いです。 

元々アクセサは、直接フィールドを設定する前や参照後に何か処理を割り込ませるために用意された仕組みです。
その処理を割り込ませたくない時には直接アクセスすることになります。

割り込ませる処理がない時でも、将来的な拡張に備えて外部I/Fについてはアクセサ経由することは多いです。
しかし、具体的にどんな処理を入れるのか見えていない時、内部アクセスをどうするべきか悩ましいです。
内部アクセスは後から変更することは容易ですし、アクセサにブレークを張ってデバッグする手法もありますから、内部からのアクセスでもアクセサ経由しておくのもありと感じます。
逆に速度を取るとか、ムダに複雑な動作をさせない等の理由で内部からはアクセサ経由しないのもありと思います。
正解はないので、あまり深く考えてても仕方がない部分かも知れません。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/09/28 22:09

    ご回答ありがとうございます。
    なるほど、とても分かりやすい理由で、とても納得できました。
    確かにC++からの移植であり、変に未使用な変数なども多いので、悩んだまま現状のような作りになった可能性もあると思います。

    あまり深く考えても仕方がない部分とのことで、ホッとしました。
    C#では無駄な処理でもC++では意味のある処理などが多く、このような設計も何か意味があるものかと考えこんでおりました。

    キャンセル

+1

私は、プロパティを使います。

public class Something(){
    public bool Flag{  
        get;  
        private set; 
    }
}

Flagはクラス内からしかセットできません。
統一感もあり、メンテしやすいです。アクセサ経由でないと触れない点も良いと思います。

プロパティの内部で例外を投げて、スタックとレースとるとわかりますが実行時はgetter,setterとして動作するようです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/09/28 22:15

    ご回答ありがとうございます。

    もしリファクタリングの機会があれば、プロパティ化したく思います。
    C#のプロパティは自動プロパティもあって便利ですよね。
    私も private set はよく使います。

    キャンセル

+1

単純に C# コンパイラが、古い時のコードじゃないですかね。

C#6以降だと、 public bool Flag { get; set; } = false; みたいに初期化もできますしね。
前は、アクセサもそのように書いてました。懐かしいです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/09/28 22:14

    ご回答ありがとうございます。

    C++からの移植コードなので、おっしゃる通り古いときのコードで、C++でのアクセサの書き方だったと思います。
    C#も最初からプロパティが存在したわけではないのですね。
    勉強になりました。

    キャンセル

+1

外のクラスに生のメンバ変数(フィールド)を公開しないというのは、一般に浸透しているイディオムですが、中で直接触るかどうかは企業の文化というか、それぞれのやりかたがあると思いますよ。

個人的な意見としては、
逆に中でも絶対にアクセサを使わないといけない規則だといろいろ面倒かなとは思います。
(メンバをそのままget;set;するだけのアクセサなら別に問題ないですが)
かと言って、特別な意味もなくメンバとアクセサを混同して使っているコードもちょっと嫌ですが。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/09/28 22:11

    ご回答ありがとうございます。

    今回のコードに関しては、場所や状況によりけりということですね。
    私個人としては、後者の「特別な意味もなくメンバとアクセサを混同しているコード」という認識でしたので、逆のことを考えることができ、とても為になりました。

    キャンセル

+1

他の方が書かれているように、現在の C# では、自動プロパティが使えるので、単純なケースではメンバ変数はそもそも存在せずクラス内からでもプロパティを使いますね。

質問のコードのようなケースの「クラス内からは変数を直接使用する」ことに、強い意味はないと思います。
理由は上記のように、そもそもそれは自動プロパティに置き換えられる(けどしてない)ので。

弱い意味なら、心情的な「クラス内なのにプロパティを経由するのはなんかムダな気がする」程度のことかと思います。

自動プロパティが使えずメンバ変数が存在しているという事は、そのプロパティの setter/getter に何らかの副作用がある(あまりよい例ではないですが、例えばプロパティ経由でset/getするとログファイルに履歴が残る、とか)ので、副作用を起こさないようにメンバ変数を直接使う、ということはあると思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/09/28 22:01

    ご回答ありがとうございます。
    はい、新しい機能などについては、自動プロパティを使用して開発を行っています。
    理由について、そこまで気にするものではないとの事で、納得できました。

    副作用についても、今後考慮して行きたいと思います。
    大元はCのコードだったらしく、歴史を感じさせると同時に影響範囲が未知のものとなっておりまして、副作用のような作りにまで気が回りませんでした。

    キャンセル

+1

引用テキストC++からの移植コードのため、プロパティとして定義されていません。

C++ の頃の名残りではないでしょうか。

もともと当該クラスでのみ使用するつもりだったんじゃないでしょうか?
なので、private で宣言。

後々、他からもアクセス可能なように public のアクセサを追加した。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/09/28 21:53

    ご回答ありがとうございます。
    ほかにも同様なコードがとても多いので、おっしゃる通りのような可能性も十分あると思います。
    「名残りなので。」と断言できるほど、C++を経験したことがないので、今回質問させていただきました。
    今後は名残りの可能性も十分考慮して理由付けしていきたいと思います。

    キャンセル

+1

移植した際にはプロパティがC#に実装されていなかったとか、Get~やSet~を使っているところの修正が大変だったとかそういった推測ができます
そこそこ新しいVisualStudioなら関数名を右クリックですべての参照を検索(だったかな?)を使うと呼び出している箇所が一気に表示されますのでちまちま置き換えるというのも可能かと思います
(その機能がなかったころの移植だと置換でやれば違うクラスの同じメンバ関数まで書き換えちゃうかもしれないので怖いという可能性があったのかと思います)
ちなみにC#のプロパティですが、内部的にはGet_プロパティ名(value)という感じで関数を作っているだけらしいので、プロパティ化しても何ら問題ないとは思われます
ちなみに強引な手段としては、Get~関数をコメントアウトして赤い波線(ビルド/コンパイルエラー)を出してIDEのエラー一覧からプロパティへ買い換えるという手もあります

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/10/01 15:00

    もとのC++で関数化して中身の書き換えを行っていたというのがどういう意図かわかりませんが、ひょっとしたら将来的にチェック機能を追加したり数値の場合は一定範囲外の場合は範囲内の抑える処理などを加える予定あるいは可能性を考慮していたのかもしれません
    これがpublicのフィールド(メンバ変数)だと代入する場所それぞれで値のチェックを行ってからの代入となりますので、チェック機能が変更した場合に何か所も書き換える必要があるために変更漏れが起こることを危惧したつくりであるかと思われます
    (ただの思い付きで決めたのかもしれませんが当事者じゃないので憶測でしか書くことはできませんが)

    キャンセル

  • 2016/10/03 20:06

    ご回答ありがとうございます。

    様々な推測、為になります。そのあたりを私一人で断言できるほど経験者ではないので、もしかしたら何かしらの深い理由があるのでは、と思い、質問させていただきました。

    キャンセル

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

  • ただいまの回答率 89.72%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る