30

C++ では、void func(const T& t)どこにでも表示されます。ただし、.NET で同様のものを見たことがありません。なんで?

構造体を使用してかなりの量のパラメーターがあることに気付きました。しかし、readonly/const の関数が表示されません。実際に試してみたので、これらのキーワードを使用して、渡されたリストを変更しないことを約束する関数を作成できませんでした。この関数がリストの内容を変更しないことを呼び出し元に約束する方法はありませんか? コードを呼び出して、このリストを変更してはいけないと言う方法はありませんか? (リストのクローンを作成したり、ドキュメントを参照したりできることはわかっていますが、コンパイル エラーが時々発生するのが好きです)

4

5 に答える 5

44

不変性は、C# が成熟しつつある領域です。これまでのところ、C# はconstC++ のセマンティクスを採用していません。これは実際には良いことだと思います。C++での の動作によりconst、希望どおりに機能するクラス階層を設計することが困難になることがよくありました。const_cast<>望ましくない constness をバイパスするためにコードが散りばめられているのを見るのは珍しいことではありませんでした。願わくば、C# の設計者が、より単純でありながら表現力のある代替手段を考案してくれることを願っています。

現在、メソッドに渡されるパラメーターまたはオブジェクトを不変としてマークする言語機能はありません。できる最善の方法は、読み取り操作のみを許可するインターフェイス (またはラッパー) を使用してオブジェクトを渡すことです。

.NET の標準コレクションの一部では、ラッパーを使用できます。このReadOnlyCollectionラッパーは、可変ICollection型を読み取り専用コンテナー内にカプセル化します。

不変型を作成するには、言語機能の計画と認識が必要です。たとえば、readonlyキーワードはあなたの友達です。クラスまたは構造体のメンバーを不変として宣言できます。残念ながら、この不変性は参照にのみ適用され、参照されるオブジェクトのメンバーには適用されません。これが意味することは、次のように宣言できるということです。

private readonly int[] m_Values = new int[100];

public void SomeMethod()
{
    m_Values = new int[50]; // illegal, won't compile!
    m_Values[10] = 42;      // perfectly legal, yet undesirable
}

上記の例では、配列への参照は不変ですが、配列の個々の要素はそうではありません。もちろん、この動作は配列を超えて拡張されます。

不変の型を設計するときに役立つと私が思った方法は、不変の動作を独自のインターフェイスに分離し、それをデータを管理するクラスによって実装することです。インターフェイスは、オブジェクトの状態を変更しないことが保証されている get プロパティとメソッドのみを公開します。その後、タイプのインスタンスをそのインターフェイス タイプのパラメータとしてメソッドに渡すことができます。これは、不変性サポートの弱い形式です。呼び出されたメソッドは、多くの場合、可変型への参照をキャストできるためです。より良いが、より面倒な代替手段は、同じインターフェースを実装し、実際のインスタンスへの参照を維持するラッパー実装を作成することです (ほとんどの場合ReadOnlyCollection)。これは手間がかかりますが、不変性をより強力に保証します。

使用するアプローチは、不変性の保証がどれほど重要であるか、およびそこに到達するためにどれだけの時間と労力を費やしても構わないと思っているかによって異なります。

このトピックの詳細に興味がある場合は、Eric Lippert がC# の不変性に関する優れた一連の記事を公開しています。

于 2010-05-11T21:04:32.427 に答える
7

constC# にはメソッド パラメーターの修飾子はありません。const 保証に似たものが必要な場合は、インターフェイスで不変型を使用できます。たとえば、メソッドはIEnumerable<T>可変コレクション タイプの代わりに を受け入れることができます。もご覧いただけますReadOnlyCollection

于 2010-05-11T20:39:07.013 に答える
5

構造体を使用してかなりの量のパラメーターがあることに気付きました。

ここで言及する価値のあることの 1 つは、値型と参照型の違いを誇張することで、C# は C++ と比較して構造体とクラスの違いを誇張していることです。C# では、すべてのクラスが参照型であり、すべての構造体が値型です。.Net では、すべてがデフォルトで値渡しされます。

値の型をこのように区別した結果、すべての値の型が関数に渡されるときにコピーされます。構造体を関数に渡す場合、関数はコピーでのみ機能するため、関数が元の構造体を変更しないことが保証されます。そのようなパラメーターに const を追加するのはばかげています。

参照型も値渡しです。または、より具体的には、参照自体が値渡しされます。したがって、参照のコピーがありますが、同じオブジェクトを指しています (参照しています)。したがって、関数によってオブジェクトに加えられた変更は、関数が終了した後も保持されます。

表面的には、const少なくとも参照型のオプションを追加することは良い考えのように思えます。少し曖昧になるのは副作用です。または、むしろ、これはどのように実施されますか? 明らかに、コードでプロパティ セッターを使用できないと言うのは簡単です。しかし、他の方法はどうですか?どのメソッド呼び出しでも、オブジェクトを変更する必要がある場合があります。プロパティのゲッターでさえ、何かを変更する副作用を持っている可能性があります (たとえば、何かが最後にアクセスされた時刻を記録するセキュリティ機能を実装するとします)。副作用のために、プロパティへの読み取りアクセスを拒否しますか?

于 2010-05-11T21:55:37.610 に答える
1

問題は、C/C++ で使用される const の正確性がコンパイラによってのみ強制されることです。そして、ところで簡単にバイパスされました。CLR は、実際には、コンパイラではなくマネージ コードにタイプ セーフを適用します。.NET フレームワークは多くの言語をサポートしているため、必然的にそうなります。型システムと対話ルールは、多くの目標とマスターを提供する必要がある共通言語インフラストラクチャである CLI に配置されています。

const の正確性は、現在の言語ではまれです。個人的には、CLI に移植されていない言語である C++ しか知りません。構文がどこにもない言語にルールを適用するのは困難です。符号なしの整数型が CLS にないという単純なことは、基本アセンブリの設計に顕著な痕跡を残しました。

不変性 (本物であり、コンパイラで偽造されたものではない) により、MSFT チームは考え続けることができます。人気があります。C# チームが検討していることは知っています。並行性などに適しています。Eric Lippert は11 部構成のブログ投稿シリーズを作成しましたが、少しずつ減っていきました。一人の男と彼の聴衆には大きすぎます。実装に向けた本格的な動きがあれば、彼らがよく考えて実行に移してくれると信じています。いつか。いくつかの言語。

于 2010-05-11T21:40:43.490 に答える
0

私が知っているように、これは簡単な方法では不可能です。この記事でいくつかのアイデアが得られるかもしれません。

http://www.c-sharpcorner.com/UploadFile/bulentozkir/PassingConstInCS11082005014622AM/PassingConstInCS.aspx

于 2010-05-11T20:42:41.127 に答える