.NET Framework - 参照トラップのコード例の共有
1 の値が等しい場合、オブジェクトもデフォルトで等しくなりますか?
.net コンテナ内の特定の referencetype の存在を判断するためのデフォルトのルールは何ですか? ポインタ値が等しいかどうかを判断します。
private static List<int> list; static void Main(string[] args) { //新建实例instance1 MyObject instance1 = new MyObject(); instance1.Value = 10; //新建list List<MyObject> list = new List<MyObject>(); //引用实例instance1 list.Add(instance1); //新建实例:instance2 MyObject instance2 = new MyObject(); //赋值为instance1.Value instance2.Value = instance1.Value; } }
使用されるModelクラス:
public class MyObject { public int Value { get; set; } }
以下のテストを行ってみましょう:
//即便Value相等,instance2与instance1的内存地址不相等! bool isExistence1 = list.Contains(instance2); //isExistence1 : false;
このテストの結果はfalseです。これは、値は同じですが、異なるメモリアドレスを指しているためです。これは「値は等しい、オブジェクトは等しくない」です。
属性 の 1 つの値に基づいて参照型が等しいかどうかを判断したい場合は、IEquatable インターフェイス を実装する必要があります。
値が等しいかどうかに基づいてオブジェクトが等しいかどうかを引き続き確認したい場合は、次の記事を参照してください: C# コンテナ、インターフェイスクラス、パフォーマンス
2 リファレンストラップ?
あるオブジェクトが別のオブジェクトを参照すると、一方が変化すると他方も変化します。たとえば、2 つの辞書をマージすると、マージ結果は正しくなりますが、元のオブジェクトが誤って変更されてしまいます。
ここに例があります:
var dict1 = new Dictionary<string, List<string>>(); dict1.Add("qaz",new List<string>(){"100"});//含有qaz键 dict1.Add("wsx",new List<string>(){"13"}); var dict2 = new Dictionary<string, List<string>>(); dict2.Add("qaz", new List<string>() { "11" });//也含有qaz键 dict2.Add("edc", new List<string>() { "17" }); //合并2个字典到dict var dictCombine = new Dictionary<string, List<string>>(); foreach (var ele in dict1) //拿到dict1 { dictCombine .Add(ele.Key,ele.Value); } foreach (var ele in dict2) //拿到dict2 { if(dictCombine.ContainsKey(ele.Key))//检查重复 dictCombine [ele.Key].AddRange(ele.Value); else { dictCombine .Add(ele.Key,ele.Value); } }
dictCombine の結果は正しいです、{"qaz", "100" and "11"}, {"wsx","13"}, {"edc"," 17 ”}
しかし、dict1 の結果はどうでしょうか? 変わってしまった! dict1 は予期せず {"qaz", "100" and "11"}, {"wsx", "13"} になりました。 正しいマージです。dict1 は変更しないでください。
理由の分析
dictCombineはまずdict1のキー値を追加します。つまり、dictCombineのキー値はすべてdict1のキー値を参照します。次に、dict2をマージするときに、まずdictCombineにキー値が含まれているかどうかを判断します。 dict2 の値が含まれている場合は、それを dictCombine のキー値に追加します。値は同じオブジェクトを参照します。つまり、この値は dict1 のキー値に追加されます。 dictCombine[ele.Key] と dict1[ele.Key] の参照が等しいかどうかの検証:
bool flag = object.ReferenceEquals(dictCombine[ele.Key], dict1[ele.Key]);//true
正しい解決策
dictCombine[ele.Key] と dict1[ele.Key] の参照が等しいことを避けてください。 ! !
Dictionary<string, List<string>> dict = new Dictionary<string, List<string>>(); //先把键都合并到dictCombine中,值都是新创建的 foreach (var key in dict1.Keys) { if (!dictCombine.ContainsKey(key)) dictCombine.Add(key, new List<string>()); } foreach (var key in dict2.Keys) { if (!dictCombine.ContainsKey(key)) dictCombine.Add(key, new List<string>()); } //分别将值添加进去 foreach (var ele in dict1) { dictCombine[ele.Key].AddRange(ele.Value); } foreach (var ele in dict2) { dictCombine[ele.Key].AddRange(ele.Value); }
dictCombine マージ結果は正しく、dict1 も dict2 も変更されていません。
概要
参照等価性を使用すると、関数間での値の受け渡し(参照による)など、多くの利点が得られます。しかし、使い方を誤ると無用なトラブルを招くことにもなります。
3 不適切な参照によりカプセル化が破壊されますか?
カプセル化されたクラスのプライベートフィールドがインターフェイスメソッドの戻り値として使用される場合、このアプローチはクラスのカプセル化を破壊することになり、これは特に無視されやすい問題です。この問題を無視すると、不可解な問題が発生する可能性があります。
以下のコードに示すように、
public class TestPrivateEncapsulate { private List<object> _refObjs; public List<object> GetRefObjs() { _refObjs = new List<object>(); ... ... //其他逻辑处理计算出来的_refObjs={1,4,2}; return _refObjs; //返回私有字段 } public object GetSumByIterRefObjs() { if (_refObjs == null) return null; foreach (var item in _refObjs) { ...//处理逻辑 } } }
先ほど書いたクラス TestPrivateEncapsulate を使用して、まずインスタンスを作成します、
TestPrivateEncapsulate test = new TestPrivateEncapsulate();
それから呼び出します:
List<object> wantedObjs = test.GetRefObjs();
返される期待されるwantedObjsには、整数型の要素が3つあるはずです。 、4、2。
続き:
List<object> sol = wantedObjs; //我们将sol指向wantedObjssol.Add(5); //加入元素5
戻って計算したいとき、wantedObjsの元の要素の合計:
test.GetSum();
予想した7ではなく、誤って12を取得してしまいました。どうしてこれなの?
注意深く分析した結果、クライアントで sol.Add(5) を呼び出した後、TestPrivateEncapsulate: _refObjs の変数を間接的に変更し、それが {1,4,2} から {1,4,2, 5 }。
クライアント側でプライベート変数が変更されました!これは、プライベート変数を返すインターフェイスの副作用です。
正解:
// 将原来的公有变为私有 private List<object> getRefObjs() { _refObjs = new List<object>(); ... ... //其他逻辑处理计算出来的_refObjs={1,4,2}; return _refObjs; //返回私有字段 } //只带只读的属性 public RefObjs { get { getRefObjs(); return _refObjs; } }
読み取り専用属性のみを持つパブリックフィールドを設定し、元のパブリックメソッドGetRefObjsをプライベートメソッドgetRefObjsに変更して、クライアント側でプライベートフィールドを変更できないようにします。
概要
オブジェクトの属性値はすべて等しいですが、オブジェクト参照は必ずしも等しいわけではありません。このオブジェクトが変更されると、すべてのリファラーの属性値も変更されます。 ;
メンバーはカプセル化された参照変数を返し、カプセル化を破棄します。
以上が.NET Framework - 参照トラップのコード例の共有の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック











この記事では、CのNull Poernter recerferenceの課題を調査します。問題は、問題はnullではなく、その誤用であると主張しています。 記事では、参照前のチェック、ポインターInitialiなど、非参照を防止するためのベストプラクティスの詳細

この記事では、printf内の\ nエスケープシーケンスを使用してcで新しいライン文字を作成し、関数を置く方法について説明します。 機能を詳しく説明し、出力のラインブレークに使用することを示すコード例を提供します。

この記事は、Cコンパイラの選択に関する初心者を案内しています。 GCCは、使いやすさ、幅広い可用性、広範なリソースが初心者に最適であるため、最適であると主張しています。 ただし、GCC、Clang、MSVC、およびTCCも比較して、その違いを強調しています

この記事では、現代のCプログラミングにおけるNullの継続的な重要性を強調しています。 進歩にもかかわらず、Nullは明示的なポインター管理にとって重要なままであり、有効なメモリアドレスがないことをマークすることにより、セグメンテーションの障害を防ぎます。 最高のPRAC

この記事では、初心者向けのオンラインCコンパイラをレビューし、使いやすさとデバッグ機能に焦点を当てています。 OnlineGDBとRepl.itは、ユーザーフレンドリーなインターフェイスと役立つデバッグツールのために強調表示されます。 プログラムやコンパイルなどのその他のオプション

この記事では、オンラインCプログラミングプラットフォームを比較し、デバッグツール、IDE機能、標準コンプライアンス、メモリ/実行の制限などの機能の違いを強調しています。 「最良の」プラットフォームはユーザーのニーズに依存していると主張しています。

この記事では、C IDEでの効率的なコードコピーについて説明します。 コピーはコンパイラ機能ではなくIDE機能であり、IDE選択ツールの使用、コード折りたたみ、検索/交換、テンプラなど、効率を向上させるための詳細戦略であることを強調しています。

この記事では、Cプログラムのコンパイルでの出力Windowsの欠落をトラブルシューティングします。 実行可能ファイルの実行に失敗し、プログラムエラー、誤ったコンパイラ設定、バックグラウンドプロセス、迅速なプログラム終了などの原因を調べます。ソリューションにはchが含まれます
