web-dev-qa-db-ja.com

C#での「constの正確さ」

Const-correctnessのポイントは、ユーザーが変更または削除できないインスタンスのビューを提供できることです。コンパイラーは、const関数内からconstnessを解除するとき、またはconstオブジェクトの非const関数を使用しようとするときに指摘することにより、これをサポートします。 constアプローチをコピーせずに、同じ目的を持つC#で使用できる方法はありますか?

私は不変性を知っていますが、名前を付けるためにコンテナーオブジェクトに実際に引き継がれるわけではありませんが、1つの例を示します。

77
tenpn

私もこの問題に何度も遭遇し、インターフェースを使用することになりました。

C#は任意の形式、あるいはC++の進化形でさえあるという考えを捨てることが重要だと思います。これらは、ほぼ同じ構文を共有する2つの異なる言語です。

私は通常、クラスの読み取り専用ビューを定義することにより、C#で「constの正確さ」を表現します。

public interface IReadOnlyCustomer
{
    String Name { get; }
    int Age { get; }
}

public class Customer : IReadOnlyCustomer
{
    private string m_name;
    private int m_age;

    public string Name
    {
        get { return m_name; }
        set { m_name = value; }
    }

    public int Age
    {
        get { return m_age; }
        set { m_age = value; }
    }
}
62
Trap

Const-craziness(または関数型プログラミング用語の純粋さ)の利点を得るには、c#のStringクラスと同様に、クラスが不変になるようにクラスを設計する必要があります。

不変クラスを使用すると、マルチタスク環境でデータを簡単に渡すことができるため、このアプローチはオブジェクトを読み取り専用としてマークするよりもはるかに優れています。

28
Sam

System.Collections.Genericsコンテナの多くに、不変のコレクションを返すAsReadOnlyメソッドがあることをお知らせしておきます。

23
Rick Minerich

C#にはそのような機能はありません。引数は、値または参照で渡すことができます。 ref修飾子を指定しない限り、参照自体は不変です。ただし、参照されるデータは不変ではありません。したがって、副作用を避けたい場合は注意が必要です。

MSDN:

パラメータを渡す

4
aku

インターフェースは答えであり、実際にはC++の「const」よりも強力です。 constは、「const」が「メンバーを設定しないか、メンバーを設定するものを呼び出さない」と定義されている問題に対する万能のソリューションです。これは、多くのシナリオでconst-nessの良い省略形ですが、すべてではありません。たとえば、一部のメンバーに基づいて値を計算するだけでなく、結果をキャッシュする関数について考えます。 C++では、これは非定数と見なされますが、ユーザーの観点からは本質的に定数です。

インターフェイスを使用すると、クラスから提供する機能の特定のサブセットをより柔軟に定義できます。 const-nessが必要ですか?変更するメソッドのないインターフェースを提供するだけです。一部の設定のみを許可し、他の設定は許可しませんか?それらのメソッドだけのインターフェースを提供します。

3
munificent

不変オブジェクトを作成するためにコンストラクターで初期化する読み取り専用フィールドを使用する他のいくつかに同意します。

    public class Customer
    {
    private readonly string m_name;
    private readonly int m_age;

    public Customer(string name, int age)
    {
        m_name = name;
        m_age = age;
    }

    public string Name
    {
        get { return m_name; }
    }

    public int Age
    {
        get { return m_age; }
    }
  }

または、プロパティにアクセススコープを追加することもできます(例:public getおよびprotected set?)

    public class Customer
    {
    private string m_name;
    private int m_age;

    protected Customer() 
    {}

    public Customer(string name, int age)
    {
        m_name = name;
        m_age = age;
    }

    public string Name
    {
        get { return m_name; }
        protected set { m_name = value; }
    }

    public int Age
    {
        get { return m_age; }
        protected set { m_age = value; }
    }
  }
3
  • constキーワードは、プリミティブ型や文字列などのコンパイル時定数に使用できます
  • readonlyキーワードは、参照型などのランタイム定数に使用できます

readonlyの問題は、参照(ポインタ)が一定であることのみを許可することです。参照(ポイント)されているものは、引き続き変更できます。これはトリッキーな部分ですが、それを回避する方法はありません。定数オブジェクトを実装するということは、変更可能なメソッドやプロパティを公開しないことを意味しますが、これは厄介です。

参照 有効なC#:C#を改善するための50の特定の方法 (項目2-constよりも読み取り専用を優先する)

2
Thomas Bratt