質問
const-correctness のポイントは、ユーザーが変更または削除できないインスタンスのビューを提供できることです。コンパイラは、const 関数内から const を破った場合、または const オブジェクトの非 const 関数を使用しようとした場合にそれを指摘することでこれをサポートします。それでは、const アプローチをコピーせずに、同じ目的を持つ C# で使用できる方法論はあるのでしょうか?
不変性については承知していますが、一例を挙げると、それがコンテナ オブジェクトに実際に引き継がれるわけではありません。
解決
私もこの問題に何度も遭遇し、最終的にインターフェイスを使用することになりました。
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; }
}
}
他のヒント
const の狂気 (関数型プログラミング用語での純粋さ) の利点を活かすには、C# の String クラスと同じように、クラスが不変になるように設計する必要があります。
このアプローチは、不変クラスを使用するとマルチタスク環境で簡単にデータを渡すことができるため、単にオブジェクトを読み取り専用としてマークするよりもはるかに優れています。
System.Collections.Generics コンテナの多くには、不変のコレクションを返す AsReadOnly メソッドがあることに注意してください。
C#にはそのような機能はありません。引数は値または参照によって渡すことができます。指定しない限り、参照自体は不変です 参照 修飾子。ただし、参照されるデータは不変ではありません。したがって、副作用を避けたい場合は注意が必要です。
MSDN:
インターフェイスがその答えであり、実際には C++ の "const" よりも強力です。const は、「const」が「メンバーを設定しない、またはメンバーを設定するものを呼び出さない」と定義されている問題に対する万能の解決策です。これは多くのシナリオで const 性を表す適切な省略表現ですが、すべてではありません。たとえば、一部のメンバーに基づいて値を計算し、結果をキャッシュする関数について考えてみましょう。C++ では、これは非 const とみなされますが、ユーザーの観点からは本質的に const です。
インターフェイスを使用すると、クラスから提供したい機能の特定のサブセットをより柔軟に定義できます。定数性が必要ですか?メソッドを変更しないインターフェイスを提供するだけです。一部の項目の設定を許可したいが、他の項目は設定できないようにしたいですか?これらのメソッドだけを備えたインターフェイスを提供します。
コンストラクターで初期化する読み取り専用フィールドを使用して不変オブジェクトを作成するという他の意見のいくつかに同意します。
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; }
}
}
- の 定数 キーワードは、プリミティブ型や文字列などのコンパイル時定数に使用できます。
- の 読み取り専用 キーワードは参照型などの実行時定数に使用できます。
問題点 読み取り専用 それは、参照 (ポインター) が定数であることのみを許可するということです。参照された(指された)ものは引き続き変更できます。これは難しい部分ですが、回避する方法はありません。定数オブジェクトを実装するということは、変更可能なメソッドやプロパティを公開しないようにすることを意味しますが、これは厄介です。
こちらも参照 効果的な C#:C# を改善するための 50 の具体的な方法 (項目 2 - const よりも readonly を優先します。)