ゲッター、セッター、プロパティのベストプラクティス。JavaとC#


92

私は今C#クラスを取得しており、最善の方法を見つけようとしています。私はJavaの出身なので、Javaのベストプラクティスにのみ精通しています。私はC#初心者です!

Javaでは、プライベートプロパティがある場合はこれを行います。

private String name;

public void setName(String name) {
   this.name = name;
}

public String getName() {
   return this.name;
}

C#では、これを行うには多くの方法があることがわかります。

私はJavaのようにそれを行うことができます:

private string name;

public void setName(string name) {
   this.name = name;
}

public string getName() {
   return this.name;
}

または私はこのようにそれを行うことができます:

private string name;

public string Name {
   get { return name; }
   set { name = value; }
}

または:

public string Name { get; set; }

どちらを使用する必要がありますか。また、各アプローチに関連する注意点や微妙な点は何ですか。クラスを作成するとき、私はJavaから知っている一般的なベストプラクティスに従っています(特に、Effective Javaを読んでいます)。たとえば、私は不変性を支持しています(必要な場合にのみセッターを提供します)。これらのプラクティスがC#でセッターとゲッターを提供するさまざまな方法にどのように適合するかを知りたいだけです。基本的に、Javaの世界のベストプラクティスをC#にどのように変換しますか?

編集する

私はこれをジョン・スキートの回答へのコメントとして投稿していましたが、長くなりました:

重要なプロパティ(つまり、重要な処理と検証を伴う)はどうですか?パブリックプロパティを介してそれを公開することはできますが、ロジックがgetandにカプセル化されていsetますか?専用のセッターメソッドとゲッターメソッド(関連する処理ロジックと検証ロジックを含む)を使用するよりも、なぜこれを行うべきですか?

回答:


88

Pre-C#6

ささいなプロパティのために、これらの最後のものを使用します。ゲッターとセッターの両方がパブリックなので、これをパブリックプロパティと呼ぶことに注意してください。

不変性は、自動的に実装されるプロパティでは少し面倒です-ゲッターのみを持つ自動プロパティを作成することはできません。あなたが来ることができる最も近いのは:

public string Foo { get; private set; }

これは実際には不変ではありませ ...クラスの外で不変です。そのため、実際の読み取り専用プロパティを代わりに使用したい場合があります。

private readonly string foo;
public string Foo { get { return foo; } }

あなたは間違いなく書きたくないgetName()setName()。では、いくつかのケースでは、彼らは高価になる可能性があります場合は特に、書き込みのget / setメソッドではなく、使用してプロパティに理にかなっている、あなたはそれを強調したいです。ただし、メソッドについてはPascalCaseの.NET命名規則に従う必要があります。また、このような自明なプロパティを通常のメソッドで実装する必要はありません。ここでは、プロパティの方がはるかに慣用的です。

C#6

やっと、ようやく適切な読み取り専用の自動的に実装されたプロパティができました。

// This can only be assigned to within the constructor
public string Foo { get; }

同様に、いくつかの作業を行う必要がある読み取り専用プロパティの場合は、メンバー本体のプロパティを使用できます。

public double Area => height * width;

5
より正確:Javaの方法が有効な言語AND(!)ランタイムコンストラクトをバイパスし、プロパティの使用をプロパティ(つまり、object.property = "value")として強制終了するハックであることを、コードが再表示すると指摘します。一部のチームでは、これは態度についての素晴らしい話になるでしょう。真剣に、言語と戦わないでください。特に、Javaの "way"は、不動産サポートのために言語を変更しないように選択されたハックであるためです。
TomTom

1
良い知らせは、私の回答があなたの言ったことと矛盾していないようだと思います。悪いニュースはあなたの指が私のものよりもはるかに速いことです。素晴らしい洞察と、追加された詳細に感謝します。
jeremyalan

4
編集に答えるには、get / setメソッドを使用して、必要なロジックをいくつでも使用できます。これは、特に検証のために頻繁に行われます。ただし、ベストプラクティスは、プロパティに低速のロジック(データベースアクセスなど)、危険なロジック(例外のスロー)、または変更(多くの状態の変更)を多数含めることではありません。プロパティは多かれ少なかれ単純な状態のように振舞うことが期待されています。それ以上のものは、代わりに関数を使用して示す必要があります。
CodexArcanum、2011

2
@rtindru:はい、私はそれを知っています。読み取り専用プロパティを書き込むことは完全に可能です。ただし、セットアクセサーがないと、自動的に実装されるプロパティを宣言できません。
Jon Skeet 2013年


17

必要なのは、いくつかのデータを格納する変数だけの場合:

public string Name { get; set; }

読み取り専用で表示したいですか?

public string Name { get; private set; }

またはさらに良い...

private readonly string _name;

...

public string Name { get { return _name; } }

プロパティを割り当てる前にいくつかの値チェックをしたいですか?

public string Name 
{
   get { return m_name; }
   set
   {
      if (value == null)
         throw new ArgumentNullException("value");

      m_name = value;
   }
}

一般に、GetXyz()とSetXyz()は特定の場合にのみ使用され、適切と思われるときにガットを使用する必要があります。一般的に、ほとんどのget / setプロパティには多くのロジックが含まれておらず、予期しない副作用があったとしてもごくわずかであると思います。プロパティ値を読み取るときに、要求しているオブジェクトを構築するためにサービスを呼び出すか、ユーザーから入力を取得する必要がある場合は、それをメソッドにラップしてBuildXyz()、ではなくのように呼び出しますGetXyz()


2
プロパティで例外をスローするのではなく、コントラクトでメソッドセッターを使用して、そのような特定の動作を指定します。プロパティがint型である場合、すべてのintが修飾されることを期待します。私によると、例外のスローを要求するものは単純ではないと思います。INotifyPropertyChanged型の呼び出しは、その行のほうが多いと私は考えています。
flindeberg 2012年

3
プライベートセッター!=不変
ピエダー2014年

piedarは正しいです。プライベートセッターは割り当てを行うことができないことを意味しますがmyList.Add()、たとえばを使用できます(オブジェクトが変更に公開されている限り、変更可能です)。

1
@flindeberg申し訳ありませんが、私は同意しません... Min/ Max値のプログレスバーがある場合はどうでしょうか。確認したいMax > Minですか?SetRange(Min, Max)理にかなっているかもしれませんが、それらの値をどのように読み戻しますか?読み取り専用の最小/最大プロパティ?無効な入力に対して例外をスローすることは、これを処理する最もクリーンな方法のようです。
基本

12

get / setメソッドではなく、C#のプロパティを使用します。彼らはあなたの便宜のためにそこにあり、それは慣用的です。

2つのC#の例と同様に、1つは単にもう1つの構文糖衣です。必要なのがインスタンス変数の単純なラッパーである場合はautoプロパティを使用し、ゲッターやセッターにロジックを追加する必要がある場合はフルバージョンを使用します。


5

C#では、getおよび/またはsetのプライベートフィールドを公開するためのプロパティを優先します。あなたが言及するフォームは、getプロパティとsetメソッドが非表示のピボットバッキングフィールドを自動的に生成する自動プロパティです。

可能な場合は自動プロパティを優先していますが、C#でset / getメソッドのペアを実行しないでください。


5
public string Name { get; set; }

これは単なる自動実装プロパティであり、技術的には通常のプロパティと同じです。コンパイル時にバッキングフィールドが作成されます。

すべてのプロパティは最終的に関数に変換されるため、最終的に実際にコンパイルされる実装は、Javaで使用されるものと同じです。

バッキングフィールドで特定の操作を行う必要がない場合は、自動実装プロパティを使用します。それ以外の場合は、通常のプロパティを使用します。操作に副作用がある場合、または計算に負荷がかかる場合は、get関数とset関数を使用し、それ以外の場合はプロパティを使用します。


4

C#でどの方法を選択しても、最終結果は同じです。ゲッターメソッドとセッターメソッドを別々に持つbackinng変数を取得します。プロパティを使用することにより、ベストプラクティスに従っているため、取得する詳細度の問題です。

個人的には、最後のバージョンである自動プロパティを選択public string Name { get; set; }しました。また、検証などを追加する必要がある場合は、いつでもこれらを拡張できます。


4

string Name { get; set; }簡潔で読みやすいので、可能な限り公開することを好みます。ただし、これが必要になる場合があります

private string name;

public string Name {
   get { return name; }
   set { name = value; }
}

2
いつ、なぜそのようなことが必要なのか説明できますか?
Jesper

今のところ、2ndバージョンを使う理由は考えられません。私は「これが必要な時かもしれない」とだけ言った。私はポジティブでない限り、絶対を使用するのは嫌いです。
SquidScareMe

3
そして、なぜこれが「lolz」なのか?賛成投票することで、コメントに対する支持を表明できます。
SquidScareMe

1
あなたが値に対してアトミック/スレッドセーフな操作をしたいときに、明示的バッキングフィールドを使用する理由の1つはある
基本

4

C#ではgetX()setX()メソッドではなくプロパティを使用する方法が推奨されます。また、C#ではプロパティにgetとsetの両方が必要なわけではないことに注意してください。get専用のプロパティとset専用のプロパティを持つことができます。

public boolean MyProperty
{
    get { return something; }
}

public boolean MyProperty
{
    set { this.something = value; }
}

4

まず、あなたが書いた内容を説明してみましょう。

// private member -- not a property
private string name;

/// public method -- not a property
public void setName(string name) {
   this.name = name;
}

/// public method -- not a property
public string getName() {
   return this.name;
}

// yes it is property structure before .Net 3.0
private string name;
public string Name {
   get { return name; }
   set { name = value; }
}

この構造は現在も使用されていますが、いくつかの追加機能を実行する場合に最適です。たとえば、値が設定されている場合、解析して大文字に変換し、内部使用の変更のためにプライベートメンバーに保存できます。

.NET Framework 3.0

// this style is introduced, which is more common, and suppose to be best
public string Name { get; set; }

//You can more customize it
public string Name
{
    get;
    private set;    // means value could be set internally, and accessed through out
}

C#での幸運を祈ります


3

前述のように、これらのアプローチはすべて同じ結果になります。最も重要なことは、慣習を選んでそれを守ることです。私は最後の2つのプロパティの例を使用することを好みます。


2

ここでのほとんどの回答と同様に、自動プロパティを使用します。直感的で、コードの行が少なく、よりクリーンです。クラスをシリアル化する必要がある場合は、クラスを[Serializable]/ [DataConract]属性でマークします。そして、あなたが使用している場合は[DataContract]、メンバーに

[DataMember(Name="aMoreFriendlyName")]
public string Name { get; set; }

プライベートまたはパブリックセッターは、ユーザーの好みによって異なります。

また、自動プロパティにはゲッターとセッター(パブリックまたはプライベート)の両方が必要です。

/*this is invalid*/
public string Name 
{ 
    get; 
   /* setter omitted to prove the point*/
}

または、取得/設定のみが必要な場合は、バッキングフィールドを自分で作成します


0

どちらを使用する必要がありますか。また、各アプローチに関連する注意点や微妙な点は何ですか。

プロパティを使用する場合、まだ言及されていない警告が1つあります。プロパティを使用すると、ゲッターまたはセッターのパラメーター化を行うことはできません。

たとえば、リストアイテムを取得し、同時にフィルターも適用したいとします。getメソッドを使用すると、次のように記述できます。

obj.getItems(filter);

対照的に、プロパティでは最初にすべてのアイテムを返す必要があります

obj.items

次のステップでフィルターを適用するか、さまざまな基準でフィルターされたアイテムを公開する専用のプロパティを追加する必要があります。これにより、すぐにAPIが膨張します。

obj.itemsFilteredByX
obj.itemsFilteredByY

たとえば、プロパティを使い始めて、obj.items後でgetter-またはsetter-parametrizationが必要である、またはクラスAPIユーザーにとって物事が簡単になることがわかったときに、時々厄介になる可能性があります。次に、APIを書き換えて、このプロパティにアクセスするコード内のすべての場所を変更するか、別の解決策を見つける必要があります。対照的に、たとえばgetメソッドでは、obj.getItems()メソッドのシグネチャを拡張するだけで、オプションの「設定」オブジェクトを受け入れることができます。たとえばobj.getItems(options)、メソッドを呼び出すすべての場所を書き直す必要はありません。

そうは言っても、C#の(自動実装された)プロパティは、ほとんどの場合パラメーター化が必要ない可能性があるため、(ここで説明されているさまざまな理由から)非常に便利なショートカットですが、この警告はそのままです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.