2

私はこれについてしばらく疑問に思っていましたが、この件に関する多くの解説を見つけることができず、自分で結論を出すことができませんでした.

オブジェクトを作成するときは、データを公開し、そのデータを操作できるようにするという点で、オブジェクトをできるだけ制限することがベスト プラクティスとして認められています。特にマルチスレッド アプリケーションで、オブジェクトを不変にできる場合は、そうすることをお勧めします。

そうは言っても、C# は、クラスの定義をはるかに単純にし、さらに重要なことに、保守を容易にすることで、この規則に従わない開発者に有利に働くようです。

次の読み取り専用の不変クラスを取ります。

public class ActiveDirectoryUser
{
    private readonly string firstName, lastName, office, username, email;

    public ActiveDirectoryUser(string firstName, string lastName, string office, string username, string email)
    {
        this.firstName = firstName;
        this.lastName = lastName;
        this.office = office;
        this.username = username;
        this.email = email;
    }

    public string FirstName
    {
        get { return firstName; }
    }

    public string LastName
    {
        get { return lastName; }
    }

    ...

    public string Email
    {
        get { return email; }
    }
}

そして、読み取り専用ではない、以下のはるかに単純な例と比較してください。

public class ActiveDirectoryUser
{
    public string FirstName
    {
        get;
        set;
    }

    public string LastName
    {
        get;
        set;
    }

    ...

    public string Email
    {
        get;
        set;
    }
}

以下でインスタンス化できるものは次のとおりです。

ActiveDirectoryUser user = 
    new ActiveDirectoryUser
       { FirstName= "Sam", LastName = "Shiles", ..., Email ="Sam@shiles.com" };

より単純な定義を考えると、コードの行が少なくなればなるほど、開発者のエラーの可能性が減り、別の開発者がコードを簡単に理解できるようになります (特に、単純な例よりも実際に近い例では)、適切なコードを作成する価値があります。コストに見合うだけの読み取り専用の不変オブジェクト?

また、他の人は、C# で不変オブジェクトを作成することは、次のような自動 esq 構文を使用して簡単にする必要があると信じていますか?

public string FirstName {get; readonly set;}
4

4 に答える 4

8

定義が単純で、コード行が少なく、開発者エラーが発生する可能性が低く、別の開発者がコードを理解しやすいことを考えると(特に、単純な例よりも実際の例の場合)、適切なコードを作成することの価値があります。読み取り専用の不変のオブジェクト、コストに見合う価値はありますか?

はい。

私はあなたが言うのを妨げるものは何もないことに注意します

int Foo { get; private set; }

次に、コンストラクターでのみセッターを使用して、プロパティの不変性を保証します。優れたオブジェクト初期化構文が得られないだけですが、コンストラクターを簡単に作成できます。

また、他の人は、C#で不変のオブジェクトを作成することは、automatic-esq構文で簡単にできるはずだと信じていますか...

はい。特に、C#言語設計チームはそれを信じています。

C#3.0は、C#をより「不変に適した」言語にする多くの機能を追加しました。匿名型、クエリ内包表記、および式ツリーは、特に不変データの「機能的」スタイルのプログラミングを促進します。また、C#をより「変更しやすい」言語にする機能も追加されました。自動プロパティ、オブジェクト初期化子、および型推論された配列が思い浮かびます。

言語設計チームは、DLRチームが不変の式ツリータイプの巨大なライブラリを作成すると同時に、これらの後者の機能によって可変オブジェクトの作成が容易になったことをよく知っています。皮肉は彼らに失われていませんでした、私はあなたを保証することができます。

不変オブジェクトを作成するためのより良い糖衣構文について、言語設計チームの周りに浮かんでいる多くの提案があります。可変性を必要とするオブジェクト初期化子が、不変である匿名型初期化子とほぼ同じ構文を持っているという事実は、探索の明らかな出発点ですが、それだけではありません。

とはいえ、もちろん、第一に、私は言語設計チームを代表して話すことはありません。第二に、Roslynプロジェクト以外のC#の将来のバージョンは発表されていません。したがって、言語の仮想的な将来のバージョンの可能な機能セットに関する推測は、まさにそれです:私の側の推測。

于 2013-01-21T16:26:24.833 に答える
3

適切な読み取り専用の不変オブジェクトを作成することの価値は、コストに見合うものですか?

それは、不変性、スレッドの安全性をどれだけ気にかけているか、他の開発者が間違いを犯さないようにどれだけ信頼しているかによって異なります。

私は反対に尋ねます.可変オブジェクトを本当に速く簡単に作成することの価値に見合うスレッドミスの可能性のコストはありますか?

于 2013-01-21T13:06:58.757 に答える
1

これらの質問について熟考するとき、私はコードをいくつかのカテゴリに分類する傾向があります。

  • アプリケーション レベル
  • 内部フレームワーク レベル
  • 公開 API レベル

アプリケーション レベルでは、クラスはほとんどの場合、プロジェクト スコープ内で特定の機能を実装するように設計されたリーフ クラスになります。それらが再利用されることはめったになく、それらへの唯一の依存関係は、アプリケーション自体の他の特定のクラスです。

ここで私は自分自身にいくらかの自由を与えます。いくつかの公共の財産は誰にも害を与えません。とにかく、すべて非常にローカライズされており、アプリケーションが変更されると、コードがどのように相互作用してこのコードに変更を加えるかを理解する必要があります。しかし、自由はずさんなことと同じではありません。

フレームワーク レベルでは、プロジェクト間で高度に再利用可能なサブシステムを意味します。長年にわたって機能することが証明されているソルト + ハッシュ パスワード クラスである可能性があります。または、いくつかのプロジェクトで依存しているサードパーティ製品全体のラッパーかもしれません。

このようなアセンブリを参照したり、ソース ファイルがソリューションに追加されたりすると、アプリケーションはそのコードの唯一のコンシューマーとして表示されます。しかし、そのコードは依然として非常に封じ込める必要があり、契約を遵守することを約束する必要があります。パブリック プロパティがオブジェクトの破損状態を許可する場合、それはかなり不自由なフレームワークであると言えます。

APIレベルでは、物事は劇的に変化します。現在、多くのサブスクライバーが長期的に使用することになっているコードを設計しています。用語と混同しないように言っておきますが、ここでの明白な候補は .NET Framework そのものです。しかし、あなたが API を提供している場合、その人々は保証付きで支払うことさえあります。簡単に悪用できない安定したシステムが本当に必要です。

私が興味深い (そして少し面白い) と思うのは、OOP 純粋主義者と SOLID 純粋主義者 (および他の純粋主義者) からもたらされたすべての優れた原則は、すべてのコードがそのハイエンド サポートにあるという仮定にデフォルトで準拠しているように見えることです。 API レベル。

あなたの質問に答えるために 考えるべきいくつかの質問をします

  • このオブジェクトは状態を変更しますか?
  • 変更によって、他のコードの部分が持っている仮定が壊れることはありますか?
  • もしそうなら、私のオブジェクトの正当な使用は実際にそのように悪用されるでしょうか?
  • 私のオブジェクトがめちゃくちゃに悪用されている場合、これはローカルのバグですか、それとも主要なサポートの問題ですか?
  • ここで実際に必要な保護レベルは?
  • そこにどれだけ力を入れるべきか。
  • これにはドキュメントが付属していますか?

明示的な例については。私が非常に誇りに思っている Web プロジェクトでは、多くのデータがシングルトン (実際には静的クラス) にキャッシュされています。GetOrSet でスレッド セーフを確保するために、正しくロックします。1つの小さな詳細を除いて。キャッシュ内の実際のオブジェクトへの参照を複数のスレッドに渡します。これらは変更可能であり、パブリック プロパティに書き込もうとすると、あらゆる種類の問題が発生する可能性があります。では、クローンを作成しますか? それらを不変にしますか?これらのオブジェクトをコピーしてパフォーマンスに影響を与えないようにしてください。いいえ。私たちは独自のキャッシュの唯一の消費者であるため、サービスからのすべてのデータを読み取り専用として扱う必要があるという決定を下しました。コピーが必要な場合は Automapper を使用します。そして、コードレビュー中にこれをチェックします。それは非常にうまく機能します。いくつかのバグがありましたが、ミュータブル オブジェクトへの書き込みによって引き起こされたものはまだありません。

患者: - このようにジャンプすると足が痛くなります。

医者: - では、そのようにジャンプしないでください!

于 2013-01-21T14:46:15.210 に答える
0

2番目の例が間違っているにもかかわらず(不変ではありません。フィールドに一致する引数を取るコンストラクターを追加する必要があります)、 readonly 修飾子は、クラスを作成したときの意図を示している可能性があります。これは、将来、他の人がクラスを変更するときに、フィールドが実質的に読み取り専用であることではなく、フィールドが読み取り専用であることを知ることを意味します。

于 2013-01-21T13:09:00.610 に答える