ホームページ バックエンド開発 C#.Net チュートリアル .NET Framework - 参照トラップのコード例の共有

.NET Framework - 参照トラップのコード例の共有

Mar 18, 2017 pm 01:39 PM

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 サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

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

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

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

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

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

C言語のnullの代替案は何ですか C言語のnullの代替案は何ですか Mar 03, 2025 pm 05:37 PM

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

次のレベルのCコンパイラを追加する方法 次のレベルのCコンパイラを追加する方法 Mar 03, 2025 pm 05:44 PM

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

どの言語コンパイラが優れていますか? どの言語コンパイラが優れていますか? Mar 03, 2025 pm 05:39 PM

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

nullは、C言語での最新のプログラミングではまだ重要ですか? nullは、C言語での最新のプログラミングではまだ重要ですか? Mar 03, 2025 pm 05:35 PM

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

C言語コンパイラのWebバージョンは何ですか? C言語コンパイラのWebバージョンは何ですか? Mar 03, 2025 pm 05:42 PM

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

c言語オンラインプログラミングウェブサイトc言語コンパイラ公式ウェブサイトの要約 c言語オンラインプログラミングウェブサイトc言語コンパイラ公式ウェブサイトの要約 Mar 03, 2025 pm 05:41 PM

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

C言語コンパイラによるコードをコピーする方法 C言語コンパイラによるコードをコピーする方法 Mar 03, 2025 pm 05:43 PM

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

C言語コンパイラによって出力ウィンドウをポップアップしないという問題を解決する方法 C言語コンパイラによって出力ウィンドウをポップアップしないという問題を解決する方法 Mar 03, 2025 pm 05:40 PM

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

See all articles