Maison  >  Article  >  développement back-end  >  Exemple de partage de code .NET Framework d'interruptions de référence

Exemple de partage de code .NET Framework d'interruptions de référence

黄舟
黄舟original
2017-03-18 13:39:481498parcourir

Les valeurs

1 sont égales, les objets sont égaux par défaut ?
Quelles sont les règles par défaut pour déterminer l'existence d'un type référence dans un conteneur .net ? Déterminez si les valeurs du pointeur sont égales.

        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;       
        }
    }

Classe Modèle utilisée :

            public class MyObject
            {
                public int Value { get; set; }
            }

Faites un test ci-dessous :

            //即便Value相等,instance2与instance1的内存地址不相等!
            bool isExistence1 = list.Contains(instance2);            //isExistence1 : false;

Ce résultat de test estfaux , car ils pointent vers des adresses mémoire différentes, bien que les valeurs​​sont égales, ce qui est le cas de "les valeurs sont égales, les objets ne sont pas égaux".
 
Si un type référence veut déterminer s'il est égal en fonction de la valeur de l'un des attributs, alors il doit implémenter l'interface IEquatable !
Si vous souhaitez continuer à voir si les objets sont égaux selon que les valeurs sont égales, veuillez vous référer à l'article : C#Conteneurs, classes d'interface, performances

2 Pièges de référence ?

 Un objet fait référence à un autre objet Quand l'un change, l'autre change . Par exemple, lors de la fusion de deux dictionnaires, le résultat de la fusion est correct, mais l'objet d'origine est accidentellement modifié.

Voici un exemple :

            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); 
                }
            }

Le résultat de dictCombine est correct, {"qaz", "100" et "11"}, { "wsx","13"}, {"edc","17"}
Mais qu'en est-il du résultat de dict1 ? J'ai été changé ! dict1 est devenu de manière inattendue {"qaz", "100" et "11"}, {"wsx", "13"}. Fusion correcte, dict1 ne doit pas être modifié !

Analyse de la raison

dictCombine ajoute d'abord la valeur clé de dict1, c'est-à-dire que la valeur clé de dictCombine fait toutes référence à la valeur clé de dict1 ; Ensuite, lors de la fusion de dict2, déterminez d'abord si dictCombine contient la clé de dict2. Si c'est le cas, ajoutez-la à la valeur clé de dictCombine. La valeur fait référence au même objet, c'est-à-dire que cette valeur est ajoutée à la clé de dict1. Vérification si les références dictCombine[ele.Key] et dict1[ele.Key] sont égales :

bool flag = object.ReferenceEquals(dictCombine[ele.Key], dict1[ele.Key]);//true

Solution correcte

Évitez dictCombine[ele.Key] et dict1 [ele.Key] Égalité de référence ! ! !

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);
            }

Le résultat de la fusion dictCombine est correct, et ni dict1 ni dict2 n'ont changé !

Résumé
  L'utilisation de l'égalité de référence apporte de nombreux avantages, tels que les références entre fonctionspassage par valeur(par référence) . Cependant, si elle est mal utilisée, elle nous apportera également des problèmes inutiles.​

3 Une référence incorrecte détruit l'encapsulation ?
 
Si le champ privé dans la classe encapsulée est utilisé comme valeur de retour de la méthode d'interface, cette approche détruira l'encapsulation de la classe, en particulier Une question qui est facilement négligée. Si vous ignorez ce problème, des problèmes inexplicables peuvent survenir.
 
 Comme le montre le code suivant,
 

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)
        {            ...//处理逻辑
        }
    }  
}

 Maintenant, en utilisant la classe TestPrivateEncapsulate que nous venons d'écrire, nous créons d'abord une instance,

TestPrivateEncapsulate test = new TestPrivateEncapsulate();

Puis appelez :

List<object> wantedObjs = test.GetRefObjs();

Les wantedObjs attendus renvoyés doivent avoir 3 éléments de type entier, 1, 4, 2.

Continuer :

List<object> sol = wantedObjs; //我们将sol指向wantedObjssol.Add(5); //加入元素5

Lorsque nous voulons revenir en arrière et calculer, la somme originale des éléments de wantedObjs :

test.GetSum();

Nous avons accidentellement obtenu 12, pas quoi nous nous attendions à 7 pouces. Pourquoi est-ce ?

Après une analyse minutieuse, nous avons constaté qu'après avoir appelé sol.Add(5) sur le client, nous avons indirectement modifié la variable dans TestPrivateEncapsulate : _refObjs, qui est passée de {1,4,2} à {1, 4,2,5}.

 Les variables privées ont été modifiées côté client ! C'est l'effet secondaire du retour de variables privées par l'interface !

 Solution correcte :

    // 将原来的公有变为私有
    private List<object> getRefObjs()
    {
        _refObjs = new List<object>();        ...
        ...
       //其他逻辑处理计算出来的_refObjs={1,4,2};    
        return _refObjs; //返回私有字段
    }

    //只带只读的属性
    public RefObjs
    {
        get
         {
            getRefObjs();            
            return _refObjs;
         }
    }

Définissez un champ public avec uniquement des attributs en lecture seule et remplacez la méthode publique d'origine GetRefObjs par la méthode privée getRefObjs . De cette façon, il est impossible de modifier les champs privés côté client !

Résumé
Les valeurs d'attribut des objets sont toutes égales, mais les références d'objet ne sont pas nécessairement égales.
Deux objets ou plus font référence à un objet. Si cet objet est modifié, les valeurs d'attribut de tous les référents sont également modifiées. ;
Member return Les variables de référence encapsulées détruiront l'encapsulation.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn