プライベートフィールドの有無にかかわらずプロパティを優先する必要がありますか?


16

現在作業しているコードベースには、プライベートフィールドとパブリックプロパティを使用する規則があります。たとえば、ほとんどのクラスのメンバーは次のように定義されています。

// Fields
private double _foo;
private double _bar;
private double _baz;

// Properties
public double Foo
{
    get{ return _foo; }
    set{ _foo = value; }
}

public double Bar
{
    get{ return _bar; }
    set{ _bar = value; }
}

public double Baz
{
    get{ return _baz; }
}

内部のプライベートプロパティがなくてもこれらを書き換えることができます。

public double Foo{ get; set; }
public double Bar{ get; set; }
public double Baz{ get; private set; }

これに関するいくつかの入力をお願いします。

  • 新しい、より簡潔なスタイルよりも古い、より明確なスタイルを好む正当な理由はありますか?
  • 簡潔なスタイルを使用して新しいクラスを作成する必要がありますか、それとも一貫性のために古いコードと一致させる必要がありますか?この場合、一貫性は古いフォーマットを正当化するのに十分な価値がありますか?

この質問と回答をご覧ください。
ピーターK.

@PeterK。有益。プログラムの残りのスタイルを維持することを心配する必要があるかどうか、またはそれが問題にならないほど小さな詳細であるかどうかは答えません。
KChaloux

@KChaloux:わかりました!それが答えではなくコメントである理由です。:-)
ピーターK.

@PeterK。Fair '
nuff

1
変更しないもう1つの理由は、WCFを使用してネットワーク上で何かが渡された場合です。自動プロパティに契約の問題があります(.NETによって作成されたバッキングフィールド名の無効な文字による)
レオン

回答:


16

いわゆる「古い」スタイルがまだ必要な場合がいくつかあります。

A:言語提供の不変性を使用した不変型。readonlyC#の修飾子は、構築後にその値を凍結します。(まだ)自動的に実装されたプロパティでこれを模倣する方法はありません。

public sealed class FooBarBazInator
{
    private readonly double foo;

    public FooBarBazInator(double foo)
    {
        this.foo = foo;
    }

    public double Foo
    {
        get
        {
            return this.foo;
        }
    }
}

B:ゲッター/セッターには、あらゆるロジックがあります。クラスにデータバインドされるWPFおよびSilverlight(および同様の)コードはINotifyPropertyChanged、次のように実装します。

public class FooBarBazInator : INotifyPropertyChanged
{
    private double foo;

    public event PropertyChangedEventHandler PropertyChanged;

    public double Foo
    {
        get
        {
            return this.foo;
        }

        set
        {
            this.foo = value;
            this.RaisePropertyChanged("Foo");
        }
    }

    private void RaisePropertyChanged(string propertyName)
    {
        var propertyChanged = this.PropertyChanged;

        if (propertyChanged != null)
        {
            propertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

それ以外は、新しいスタイルを使用すると思います。コードを簡潔に保ち、バグが入り込む表面積を小さくします。さらに、ロジックを含めるために変更する必要がある場合、署名と互換性がありません。


2
誰もが新しいスタイルを採用することに同意しているようです。readonly修飾子が付いたフィールドの必要性について私に知らせると、+ 1と回答クレジットが得られますが、これは知りませんでした。= D
KChaloux

3
一部の人(私を含む)は、不変のプロパティに対して「十分な」プライベートアクセサを持つ自動プロパティを検討します。確かに、それらは真に不変ではないかもしれませんが、コンストラクタの外でセッターを使用しないように注意する必要があります。
svick

2
別の理由はref、プロパティで機能しない値を渡す場合です。したがって、フィールドが必要です
-stijn

1
FodyのようなツールINotifyPropertyChangedは、明示的なバッキングフィールドを必要とせずに実装できます。github.com/Fody/PropertyChanged
セバスチャン・レッド

3
注意:C#6では、 "getter-only auto-properties"を許可しています。これにより、私の例 "A"が実行していることを1行で提供します。
ジェシーC.スライサー

6

バッキングフィールドを明示的に指定することは無意味です。コードが長くなり、読みにくくなります。また、エラーの可能性が追加されます。

public double Bar
{
    get { return _baz; }
    set { _bar = value; }
}

このようなエラーは非常に簡単に発生する可能性があり、見つけるのは非常に難しいと思います。

一貫性が必要な場合は、別の方法で行います。バッキングフィールドを使用するコードを自動プロパティを使用するコードに変更します。ReSharperのようなリファクタリングツールを使用する場合、これは特に簡単です(そのようなものを使用しない場合は、開始する必要があると思います)。

もちろん、バッキングフィールドが必要な場合もありますが、この質問には関係ないと思います。


コードをリファクタリングするときに、いくつかの古いフィールドで実際にそれを行いました...それは苦痛です。
KChaloux

1

質問はかなり古いものですが、ここで言及する価値のある本から読んだいくつかのポイントを追加することを考えました。

  1. ランタイムシリアル化エンジンは、シリアル化されたストリームにフィールドの名前を保持します。自動実装プロパティ(AIP)のバッキングフィールドの名前はコンパイラーによって決定され、コードを再コンパイルするたびにこのバッキングフィールドの名前を実際に変更する可能性があります。 AIP。したがって、シリアライズまたはデシリアライズする予定のタイプでAIPを使用しないでください。

  2. デバッグ時には、AIPのgetメソッドまたはsetメソッドにブレークポイントを設定できないため、アプリケーションがこのプロパティを取得または設定するタイミングを簡単に検出できません。手動で実装されたブレークポイントにブレークポイントを設定できます


3
#1-ほとんどのシリアライザーはデフォルトでプライベートプロパティ/フィールドを無視します。あなたが言及した問題に遭遇したことはありません。#2-これはVS2015で修正され、VS2013で回避できます。参照してください。このVisual Studioの雑誌の記事を
ブライアン

-3

新しい、より簡潔なスタイルよりも古い、より明確なスタイルを好む正当な理由はありますか?

あんまり。私はあなたがそのようなパススループロパティを持っているときはいつでも、最初からパブリックフィールドを使用するべきだと主張します。

簡潔なスタイルを使用して新しいクラスを作成する必要がありますか、それとも一貫性のために古いコードと一致させる必要がありますか?この場合、一貫性は古いフォーマットを正当化するのに十分な価値がありますか?

上記のアドバイスを無視し、パススループロパティを持っていると仮定すると、スタイルを一致させるつもりはありません。理想的には、一貫性を保つために古いスタイルを新しいスタイルにリファクタリングしますが、そのコードを誤解する可能性はわずかです。



@svick-ああ。型に反映する場合を除き、違いはありません。タイプをサービスまたはライブラリインターフェースとして公開している場合は、とにかくプロパティを必要とするインターフェースを公開します。OPはこれらのことを何もしていません。
テラスティン

2
これらの限られたケースには技術的な理由はありません。デバッガー、クラス図、インテリセンスでプロパティの動作が異なることを忘れないでください。リフレクションを実行していないと思われるときは、.NETフレームワークがそうです。WinForms、WPF、および他のいくつかのコンポーネントは、内部的にリフレクションを使用し、プロパティを個別に処理するため、パブリックサイトを使用するためのアドバイスは、このサイトの多くの開発者に受け入れられません。
ケビンマコーミック

1
@KevinMcCormickとフレームワークは、フィールドで(私が理解していることから)完全にうまく動作します。自動プロパティが存在するため、それは実際には重要ではありませんが、大きな問題はそもそも物を公開することです。物事をプロパティにするだけで、「公共の場を作らないで」ということからそれを無理にすると考える人があまりにも多くいます。
テラスティン

2
フレームワークはそれらを異なる方法で処理します:EF POCOでパブリックフィールドを使用する、DataGridViewにバインドする、PropertyGridを使用する、など。何百回も、しかしGetFieldにはそうではありません。要するに、これらは異なり、パブリックデータに常にプロパティを使用することの推奨は、この事実に一部基づいています。これはフィールドの使用を妨げるものではありませんが、その場合は正当化が必要です。ただし、パブリックデータを不注意に公開することは常に悪い考えです。
ケビンマコーミック
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.