publicとprivateでプロパティとフィールドを使い分ける

「プロパティを利用する場面とフィールドを利用する場面で混乱してしまう」

あるいは

「フィールドのほうが簡潔に記述できるのに、あえてプロパティを利用する理由がちょっとわからない」

そんな疑問を、もったことはないでしょうか。

データを持つという意味で、プロパティとフィールドに違いはないのですけども

それでも、C#ではフィールドではなく、プロパティを使うほうが適している場面があります。

本記事は、プログラムの書き方を強制する内容ではありません。

しかし、プロパティとフィールドの使い分けに困っている人の参考になればと書いております。

それでは本文をご覧ください。

publicとprivateでプロパティとフィールドを使い分ける

最初に、プロパティとフィールドの使い分け方法についてです。

publicならプロパティ
privateならフィールド

です。

publicのフィールドがダメというわけではありませんし、
もちろん、privateでプロパティを使う場面がないとは言いません。

冒頭でも述べましたが、プログラムの書き方を強制する内容ではありません。

それでも、使い分けにお困りであれば、
まずは、publicならプロパティ、privateならフィールドにすることをお勧めします。

では、その理由を見ていきましょう。

C#初期にみるプロパティとフィールドの関係

プロパティはクラスの外側とフィールドの橋渡しをしています。

今のC#のプロパティ表記はシンプルです。

しかし、シンプルがゆえにプロパティがどのようにフィールドと関わっているのか見えづらくなっています。

省略して書き安くなっているプロパティは、昔どのように書かれていたのか

黎明期の記述方法を改めてみてみましょう。


プロパティが、クラスの中に隠されているフィールドと、クラスの外とのやり取りを担っていますね。

これが、publicならプロパティ、privateならフィールドにする一つの理由です。

プロパティは「インターフェース」で使われる

外からの変更を受けるときには、フィールドではなくプロパティが適している理由はもう一つあります。

それが、C#のinterfaceです。

試しに、プロパティとフィールドをinterfaceで定義してみましょう。

プロパティは定義できましたが、フィールドはコンパイルエラーを発生させます。

これは、C#の仕様としても、インターフェースとしての役割をフィールドに求めていないということです。

  • インターフェースの定義でもフィールドを利用することができないこと、
  • 昔の記述方法では、フィールドがPrivate、プロパティがPublicで書かれていること

からも、プロパティとフィールドの役割の違いをわかっていただけたのではないでしょうか。

プロパティにできてフィールドにできないこと

プロパティでできることが、フィールドではできないことがあります。

実用的に使える例もいくつか紹介します。

プロパティは値変更を検出できる

get,setにはブレークポイントがおけるので、
値が変わるとき、取得される時をデバッガーで検知できます。

この動きはフィールドにはできない動きです。

今回は、setにブレークポイントを挿入している例です。

Nameプロパティが変更されるときに、止めることができます。

また、変更前後の値を比較することが可能です。

セットされる予定の値には、変数名valueが与えられていて、
もともとの値はプロパティ名で今回の場合はNameで確認できるので、変更前後を比較できます。

今回はsetについて紹介しましたが、
もちろんgetにもブレークポイントを置くことができるので、
値が呼び出されることを検知したい方は試してみてください。

プロパティはログが置ける

また、プロパティはログを記載することが可能です。

フィールドではできない、処理の記述が

get,setではできるため、ログを残すことができるわけです。

不具合が起きた時などに、プロパティにログを仕込むことで原因究明の手助けになります。

しかし、フィールドを使うと難しいでしょう。

publicフィールドはAPIでJSON出力対象外

publicプロパティでできて、publicフィールドではできないこと。

その一つがApiでのjson出力です。

APIチュートリアルで試してましょう。

チュートリアルは、「WeatherForecast」をjson形式で出力してくれます。
チュートリアル開始時点ですべての項目がプロパティで定義してあります。

このAPIを起動するとjsonを出力します。こんな感じです。

Date、TemperatureC、TemperatureF、Summaryすべて出力されました。

では試しにTemperatureCをpublicフィールドに変えてみましょう。すると

TemperatureCの項目が消えてしまいました。

このように仕組みとして、Publicフィールドをサポートしていない機能があるということです。

もし、意図せずPublicフィールドを使っているのであれば、
なぜjson出力できないのか調査する羽目になります。

特にこだわりがないなら、PublicフィールドよりPublicプロパティを使うことをおすすめします。

プロパティとフィールドのサポートの範囲に振り回されないために

コーディング途中にフィールドが使えるのか使えないのか判断していくのは大変ではないでしょうか。

publicプロパティでできて、publicフィールドではできないこと。
の一例としてAPIを上げました。

他にも、プロパティには、クラスのインターフェースとしての役割があるからか、
xml,json,db,ui,etcプログラムの境界・入出力で活躍する機能にはプロパティ前提のものがあり、
フィールドをサポートしていないことがあります。

例えば、WPFなどで使われる、データバインドです。

データバインドすることで、画面に表示する項目を変えたりすることができるのですが、

フィールドはデータバインドできないと明記されています。

ターゲット プロパティは、依存関係プロパティである必要があります。 これは、フィールドをバインドできないことも意味します。

https://docs.microsoft.com/ja-jp/dotnet/api/system.windows.data.binding?view=net-5.0

もちろん、プログラムの境界・入出力で利用される機能の中には、Publicフィールドをサポートしているものもあります。

しかし、すべてではありません。

この機能はフィールドOK,そっちの機能はフィールドNGと考えるよりは、
一律プロパティにしたほうが考えることが少なくて済む
かもしれませんね。

まとめ

最後にまとめます。

  • 外向けにPublicプロパティ
  • 内向けにPrivateフィールド
  • interfaceはプロパティしか使えない
  • publicフィールドでは動かない機能がある

メンドクサイでパブリックフィールドを使って、
プログラムに大した影響がないならフィールドでも問題ないと考えています。

しかしながら、interfaceを利用したり、データバインドを利用しようとしたときに弊害になるので、

こだわりのない場合は、Publicならプロパティ、Privateならフィールドの使い分けてみてはいかがでしょう。

では。