2016-10-03 11 views
0

私はCMMIレベル5の会社のインタビューで、C#で可変で不変のクラスを作成する方法について質問されました。私は文字列のStringBuilderのように、を変更することはできません変更することができることを意味可変と不変の聞いたことがあります。変更可能なクラスとは何ですか? C#で可変で不変のクラスを作成するにはどうすればいいですか

しかし、私は可変クラスと不変クラスを作成する方法を知らなかった。これにはStringとStringのビルダーがあります。しかし、それを作成することについては、私はこれをウェブで検索することを余儀なくされましたが、有用なものは何も見つかりませんでしたので、ここで質問しました。

しかし、私はクラスのプロパティを定義することでそれを作成しようとしました。そのゲッターでは、それを複製する新しい文字列オブジェクトを作成しました。しかし、理解に成功しなかった。

また、私は、不変で変更可能であることについて、すでにstackoverflowで質問されていることを言及しました。しかし、私の質問は異なっています。私は変更可能なクラスを作成したいのかどうかを知りたかったのですが、Stringクラスやその他の変更可能なクラスを使用する方法とは別にどうやって行くのでしょうか。

+0

[変更可能と不変の違いは何ですか?](http://stackoverflow.com/questions/3811016/what-is-the-difference-between-mutable-and-不変) – walther

+0

投稿する前に回答を検索して、重複した質問をしないでください。 – walther

+0

@walther:私の質問をお読みください!私は可変クラスを作る方法を尋ねました。私は変更可能で不変なものを知っています。しかし、それが作成になると、私はそれについて知りません。あなたが言った質問は違う! – Yash

答えて

2

C#は、C++が提供する(コード契約を無視して)constの正解をサポートしていませんが、readonly修飾子(およびC#6.0の真の読み取り専用自動プロパティ)を提供します。 。

C#にはレコードタイプの構文サポートもありませんが、残念ながらC#7から引き出されていますので、もう1年待たなければなりません。

とにかく、.NETの不変型は、作成後に状態を変更できないPOCOだけです。これは、タイプにreadonlyとタグ付けされたすべてのフィールドがあり、すべての複合(つまり非スカラー)メンバーも同様に制約されている場合にのみ、コンパイラまたはランタイムによって適用されることに注意してください。ああ、あなたは配列メンバーを持つことはできません。なぜなら、C#での読み取り専用バッファの強制もないからです。これは、実際には、C#の「不変」型は、消費者(規則に従うことになる(反射がないなど))が、いつ使用するかについてある仮定を行うことができる、うまく設計されたPOCOであることを意味します。不変型は本質的にスレッドセーフです。しかし、それだけです。特別なAOTまたはJITの最適化も、ランタイムによって示される特別な動作もありません。それは非常に "人間の要因" - キンダのことです。

以下このクラスは不変です:

class Immutable { 
    private readonly String foo; 

    public Immutable(String foo, String bar) { 
     this.foo = foo; 
     this.Bar = bar; 
    } 

    public String Bar { get: } 

    public String Baz { get { return this.foo.Substring(0, 2); } } 
} 

すべてのフィールド(すなわち、そのインスタンスの状態は)readonlyと不変(System.Stringがうまく不変であることが知られているので、我々はこれだけを知っている)の両方であるので、それは不変です。 fooStringBuilderまたはXmlElementに変更された場合、それはもはや不変ではありません。厳密に言えば、readonly修飾子は不変のために必要ではありません

注、それだけで実証することが容易になり、それはコンパイル時の強制(およびおそらくいくつかのランタイムの最適化)のいくつかのレベルを追加しません。比較のために、このクラスは不変ではありません(つまり、このクラスは不変ではありません)。それは)変更可能である。

class Mutable { 
    private readonly Int32[] values; 
    public Mutable(Int32 values) { 
     this.values = values; 
    } 

    public Int32[] GetValues() { 
     return this.values; 
    } 
} 

ため可変である:

  • 変更可能である

    1. Int32[](配列型)それはA受け入れるGetValues
    2. 介して可変配列への参照を返します建設中に変更可能なオブジェクトパラメータ。

    ここでは不変ではない理由を証明する例を示します

    Int32[] values = { 0, 1, 2, 3 }; 
    Mutable mutable = new Mutable(values); 
    
    Print(mutable.GetValues()); // prints "0, 1, 2, 3" 
    
    values[0] = 5; 
    
    Print(mutable.GetValues()); // prints "5, 1, 2, 3" 
    

    Mutableが不変であればMutableのAPIを使用した場合、その後values以降の変更は見えない。Printへの2回目の呼び出しが表示されます最初の出力と同じ出力。

    しかし、配列や複合型を使用していても、不変型を持つことができます。これは、状態を変更するためのすべての方法を隠すことによって行われます。たとえば、Int32[]の代わりにReadOnlyCollection<Int32>を返し、渡されたすべての複雑で変更可能な値のディープコピー/クローンを常に実行します。しかし、コンパイラ、JIT、およびランタイムは、これがオブジェクト型を不変にレンダリングするかどうかを判断するにはまだ洗練されていません。なぜそれを文書化し、消費者が正しく使用するように信用しなければならないのですか?彼らはそれを正しく実装しました)

  • +0

    大変ありがとうございます。それは本当に助けました – Yash

    +0

    @あなたは投稿して以来、私は大幅に私の答えを延長している。 – Dai

    +0

    readonlyキーワードをコンストラクタでのみ設定できるようにすることで完全に説明できました。また、これにより、誤ってフィールドの1つを変更して不変性を破らないようにします。 – Yash