web-dev-qa-db-ja.com

C#に不変の署名を組み込む?

これは主観的な質問だと思いますが、F#と関数型プログラミングを勉強した後、不変性の利点を見てきました。

今、私は特に必要でない限り、C#で完全に可変性を取り除くことを考えています。本質的に、以前は次のようなシグネチャを持つ関数を記述した可能性があります-

public static int F(List<string> input)

私が望んでいない限り、その関数がリストを変更する可能性がある場合、私は今は偏執狂的です。だから今私は何かのようなことを考えています

public static int F(ImmutableList<string> input)

また、実際にリストを変更したい場合は、次のようなことをする前に

public static void F(List<string> input)

そしてそれを直接変更しますが、今は代わりにこのようなことをすることを考えています:

public static ImmutableList<string> F(ImmutableList<string> input)

新しいリストを再割り当てするだけです。

不変性の利点があっても、C#でこのパターンが普及することはありません。 C#でこのような関数シグネチャに移行するのは間違っているのではないかと思います。理由がある場合、これはそれほど普及していませんか?

4
user4779

人々はそれが簡単に好きです

不変性の利点があっても、C#でこのパターンが広く見られることはありません

これは技術的な考慮事項ではなく、人間によるものです。開発を忘れても、人々は一般に、個別に特化した救済策よりも万能薬を好むでしょう。なぜなら、何をいつ使うかを覚えておかなければならないより、常に同じものを使う方が簡単だからです。 「ダクトテープとWD-40で十分」という冗談は、その良い例です。

最も基本的なレベルでは、List<>の使用法が表示されます。これは、取得しようとしている万能薬に最も近いためです。同じオブジェクトに対する完全なCRUD操作です。データ収集界の「ダクトテープとWD-40」です。
そして些細な(私はこれを強調することはできません)プロジェクトの場合、それで十分です。小規模なプロジェクトは、コレクションが変更されている場所や場所がわからないような複雑さはありません。私は30時間のプロジェクトについて話している。ここでは、コンソールアプリを組み合わせて短い仕事を自動化している。専門的なものはなく、期待される長い寿命もある。

開発者が使用したいコレクションのさまざまなタイプ/インターフェースの数は、開発者がそれらをどのように区別したいかによって異なります。私はどこに線を引くべきかについては議論していません。私は、より専門的なコレクション型を使用することが、あなたが期待するほど広く普及していない理由を説明します。

多くの場合、基本的な不変性で十分です

IEnumerable<T>(通常は次のステップです)を使用して、すべてをカバーするつもりはないことを認識していますList<>)を使用するだけで、ほとんどの場合、不変性の妥当な期待にあなたを導きます。

呼び出し元が、渡したIEnumerable<>が実際にList<>であることを理解することは不可能ではないため、コールバックしてコレクションを変更し始めることができます。あなたはそれを避けたいでしょう、それは不変性のより強い実施でコレクション型に頼らなければならないことを意味します。

ただし、最初にIEnumerable<>のキャストが重要な問題であるかどうかを自問する必要があります。これは本当に弱点を露呈していますか?

  • 時々答えはイエスになります(例えば、同じリストオブジェクトが他の場所で使用されている場合、呼び出し元が信頼できない場合)、
  • ときどき答えはノーになります(たとえば、このリストオブジェクトがこの呼び出し元のために特別に生成され、呼び出し元が信頼できる場合に再利用されない場合)。

費用対利益

上記の質問に対する答えが「いいえ」の場合、他の種類のコレクションを評価する手間をかけたくない場合があります。これに多くの時間を費やしても、大きな価値はありません。

上記の質問に対する答えが「はい」の場合、IReadOnlyList<>IReadOnlyCollection<>などの読み取り専用のコレクション型を適用することを検討することができます。これにより、他の人が変更を開始することを心配することなく、同じコレクションオブジェクトを再利用できます。

C#でこのような関数シグネチャに移行するのは間違っているのではないかと思います。理由がある場合、これはそれほど普及していませんか?

これは費用便益分析です。 AがBよりも優れているからといって、Bの代わりにAを使用するのにかかる時間を費やす価値があるとは限りません。

あなたは不変性を非常に重視しているようですが、あなたと同じくらいそれを気にしない開発者はたくさんいますし、彼らはあなたとは非常に異なる費用便益分析を思いつくでしょう。

これはプロジェクトの範囲と期待に依存することに注意してください。エンタープライズアーキテクチャを設定している場合は、コードベースが必然的に1人が追跡できる範囲を超えた場合に問題を防ぐために、最初から変更不可を直ちに適用する傾向があります。しかし、小さな個人的なプロジェクトでは、何かをポリシングするよりも問題が少ないと思われるものをポリシングするための労力を費やしても意味がありません。

要約する

そのルートを自由に進んでください。そうすることに何の問題もありません。特定のニーズに合ったタイプがすでにある可能性が高いので、既存のコレクションタイプを確認することをお勧めします。

しかし、なぜそれが他の.NET開発者によってまだ使用されていないのかと尋ねたところ、それがこの回答の対象です。要約する:

  • すべての開発者が不変性を気にするわけではありません
  • 貧乏人の不変性(IEnumerable<>)で十分な場合が多い
  • 不変性を実装する努力は、常にそれだけの価値があるわけではありません。しかし、それは非常に状況依存的であり、非常に主観的です。
  • ブランケットの不変性は常に何かを行うための最良の(または実用的な)方法とは限りません

余談として...

しかし、F#と関数型プログラミングを研究した後、不変性の利点を見てきました。今、私は可変性を完全にC#で取り除くことを考えています

これは私のように聞こえます。私は今学んだことを使いたくてとても敏感です。新しい方法論やライブラリを学ぶたびに、同じサイクルを繰り返します。

しかし、私はこれらのケースの大部分で、この新しいアプローチを厳密に実装した後(そしてそれを少し伝道しすぎた場合もある)、それは必ずしも努力に値するわけではないことや、「 、しかしそれは実用的ではありません。」.

私はあなたを落胆させるつもりはありません。不変性には確かにその特典があり、それを実装する価値があります。そして、常に新しいことに挑戦してコーディングスキルを向上させるように努めるべきです。

ツールを使いたいという熱意が、必ずしも現在使用したいだけのツールを使用する必要があるとは限らないことを指摘しようと思います。理論的にエレガントなものの両方が実際に実用的であることはまれであり、(悲しいことに)実用性はどちらか一方の場合に勝つ傾向があります。

8
Flater

実際にはかなり一般的なパターンです。例えば。

public static string Concat (ReadOnlySpan<char> str0, ReadOnlySpan<char> str1, ReadOnlySpan<char> str2);

人々のコードでこれがあまり見られない理由は、可変性が非常に便利だからです。特にリストでは、常に物事を追加したり削除したりします。

誰もが機能的なクールな援助を飲んだわけではありません。

6
Ewan