web-dev-qa-db-ja.com

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

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

// 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; }

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

  • 古い、より明確なスタイルを新しい、より簡潔なスタイルよりも好む正当な理由はありますか?
  • 簡潔なスタイルを使用して新しいクラスを作成する必要がありますか、それとも古いコードと一致させて一貫性を保つ必要がありますか?この場合、一貫性は古い形式を正当化するのに十分ですか?
16
KChaloux

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

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

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));
        }
    }
}

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

16
Jesse C. Slicer

バッキングフィールドを明示的に指定しても意味がありません。コードが長くなり、読みにくくなります。エラーの可能性も追加します。

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

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

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

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

6
svick

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

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

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

1
Ram