.net 引数 - C#の構造体が不変なのはなぜですか?




span<t> 不変オブジェクト (5)

このテーマに興味がある場合は、 http://blogs.msdn.com/b/ericlippert/archive/tags/immutability/不変プログラミングに関する記事が多数あります。

構造体や文字列などが不変である理由を知りたいだけなのですか?

構造体とクラスはデフォルトでは不変ではありませんが、構造体を変更できないようにするのがベストプラクティスです。 私は不変クラスも好きです。

文字列は不変です。

それらを不変にし、オブジェクトの残りを変更可能にする理由は何ですか?

すべての型を不変にする理由:

  • 変更されないオブジェクトについては、理由を付ける方が簡単です。 3つの項目があるキューがある場合は、今は空ではないことが分かっています.5分前に空ではなく、将来空ではありません。 それは不変です! 一度私はそれについての事実を知って、私はその事実を永遠に使用することができます。 不変オブジェクトに関する事実は古くはありません。

  • 最初の点の特別な場合:不変オブジェクトはスレッドセーフを作る方がはるかに簡単です。 ほとんどのスレッドの安全上の問題は、あるスレッドでの書き込みと別のスレッドでの読み取りによるものです。 不変オブジェクトには書き込みがありません。

  • 変更不能なオブジェクトは、分離して再利用することができます。 たとえば、不変のバイナリツリーを使用している場合、左と右のサブツリーを別のツリーのサブツリーとして使用することができます。 変更可能な構造では、ある論理オブジェクトへの変更が別の論理オブジェクトに影響することを望まないため、通常はデータのコピーを作成して再利用することになります。 これにより、 多くの時間とメモリを節約できます。

構造体を変更不能にする理由

構造体を不変にする理由はたくさんあります。 ここに一つだけあります。

構造体は、参照ではなく値によってコピーされます。 誤って構造体を参照によってコピーされるものとして扱うのは簡単です。 例えば:

void M()
{
    S s = whatever;
    ... lots of code ...
    s.Mutate();
    ... lots more code ...
    Console.WriteLine(s.Foo);
    ...
}

今度は、そのコードの一部をヘルパーメソッドにリファクタリングする必要があります:

void Helper(S s)
{
    ... lots of code ...
    s.Mutate();
    ... lots more code ...
}

違う! それは(ref S)でなければなりません - あなたがそれをしなければ、sのコピーで突然変異が起こります。 最初に突然変異を許可しないと、これらの問題はすべて消えてしまいます。

文字列を不変にする理由

事実を維持している不変の構造についての事実についての私の最初の点を覚えていますか?

文字列が変更可能であるとします。

public static File OpenFile(string filename)
{
    if (!HasPermission(filename)) throw new SecurityException();
    return InternalOpenFile(filename);
}

セキュリティチェックの後でファイルが開かれる前に 、敵対的な呼び出し元がファイル名を変更するとどうなりますか? コードは、アクセス権のないファイルを開いたばかりです。

ここでもまた、変更可能なデータは理由を説明するのが難しいです。 「この呼び出し元は、この文字列で記述されたファイルを見る権限があります」という事実は、突然変異が起きるまでではなく、 永遠に真実であることが必要です。 変更可能な文字列を使用すると、安全なコードを書くために、われわれが常に知っているデータのコピーを変更しなくてはなりません。

オブジェクトを不変にすると考えられるものは何ですか?

型は論理的に "永遠の"値であるものを表現していますか? 数字12は数字12です。 それは変わらない。 整数は不変でなければならない。 点(10,30)は点(10,30)です。 それは変わらない。 ポイントは不変でなければなりません。 文字列 "abc"は文字列 "abc"です。 それは変わらない。 文字列は不変でなければなりません。 リスト(10,20,30)は変更されません。 等々。

時々タイプは変化するものを表します。 メアリー・スミスの姓はスミスだが、明日はメアリー・ジョーンズとなるかもしれない。 またはミス・スミスは今日明日のスミス・スミスかもしれません。 エイリアンは今50ヘルスポイントを持っていますが、レーザービームに当たった後は10ポイントあります。 いくつかは突然変異として最もよく表されます。

変更可能オブジェクトと不変オブジェクトのメモリの割り当て方法と割り当て解除方法に違いはありますか?

そうではありません。 しかし、前にも触れましたが、不変の価値に関する素晴らしい点の1つは、コピーを作成せずにそれらの部分を再利用できることです。 その意味で、メモリの割り当ては非常に異なる場合があります。

構造体や文字列などが不変である理由を知りたいだけなのですか? それらを不変にし、オブジェクトの残りを変更可能にする理由は何ですか? オブジェクトを不変にすると考えられるものは何ですか?

変更可能オブジェクトと不変オブジェクトのメモリの割り当て方法と割り当て解除方法に違いはありますか?


構造体型は不変ではありません。 はい、文字列があります。 独自の型を不変にすることは簡単です。既定のコンストラクタを提供せず、すべてのフィールドをプライベートにし、フィールド値を変更するメソッドやプロパティを定義しないでください。 オブジェクトを変更するメソッドは、代わりに新しいオブジェクトを返す必要があります。 メモリ管理の角度があり、コピーやゴミをたくさん作成する傾向があります。


Structsはそうではありません...それはなぜ可変構造体が悪いのかです。

変更可能な構造体を作成すると、アプリケーションであらゆる種類の奇妙な動作が発生する可能性があるため、非常に悪い考えです(参照型のように見えますが、実際には値型で、渡すたびにコピーされますそれらの周り)。

一方、ストリングスはあります。 これにより、本質的にスレッドセーフであり、文字列のインターナショナルによる最適化が可能になります。 複雑な文字列をオンザフライで構築する必要がある場合は、 StringBuilderを使用できます。


構造体は変更可能ですが、コピーセマンティクスを持っているため、構造体は変更できません。 構造体を変更した場合は、実際にコピーを変更している可能性があります。 変更された内容を正確に把握するのは非常に難しい作業です。

変更可能な構造体はミスを犯します。


私は、管理されたリソースと管理されていないリソースの両方でIDisposableを使用することについて、多くの回答が話題に移っていることがわかります。私はIDisposableが実際にどのように使われるべきかについて私が見いだした最良の説明の1つとして、この記事を提案します。

https://www.codeproject.com/Articles/29534/IDisposable-What-Your-Mother-Never-Told-You-About

実際の質問については、あなたはIDisposableを使用して多くのメモリを占有している管理対象オブジェクトをクリーンアップしなければなりません。その理由は、IDisposableをDisposeすると、そのIDisposableを範囲外にする必要があるからです。その時点で、参照されている子オブジェクトも範囲外であり、収集されます。

実際の例外は、管理されたオブジェクトにたくさんのメモリを抱えていて、そのスレッドが処理を待つのをブロックした場合です。呼び出しが完了した後でそれらのオブジェクトが必要ない場合は、これらの参照をnullに設定すると、ガーベジコレクターはそれらをより早く収集することができます。しかし、このシナリオは、IDisposableの使用例ではなく、リファクタリングする必要のある悪いコードを表します。





c# .net immutability