3 réflexions sur la référence C# en détail

黄舟
Libérer: 2017-03-04 10:53:59
original
1736 Les gens l'ont consulté

1 Si les valeurs sont égales, les objets seront égaux par défaut ?

Quelles sont les règles par défaut pour déterminer l'existence d'un type référence dans le 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;       
        }
    }
Copier après la connexion

Classe modèle utilisée :

            public class MyObject
            {
                public int Value { get; set; }
            }
Copier après la connexion

Faites un test ci-dessous :

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

Ce résultat de test est faux , car ils pointer vers des adresses mémoire différentes, bien que les valeurs soient égales, c'est le cas de "Des valeurs égales, mais pas des objets égaux" .
 
Si un type référence veut déterminer s'il est égal en fonction de l'une de ses valeurs d'attribut, 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 : Conteneur C#, classe d'interface, performances

2 Piège 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); 
                }
            }
Copier après la connexion

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
Copier après la connexion

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);
            }
Copier après la connexion

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, comme par exemple le transfert de référence entre fonctions. 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)
        {            ...//处理逻辑
        }
    }  
}
Copier après la connexion

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

TestPrivateEncapsulate test = new TestPrivateEncapsulate();
Copier après la connexion

Puis appelez :

List<object> wantedObjs = test.GetRefObjs();
Copier après la connexion

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
Copier après la connexion

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

test.GetSum();
Copier après la connexion

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;
         }
    }
Copier après la connexion

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 l'introduction détaillée des trois pensées de C#reference. Pour plus de contenu connexe, veuillez faire attention au site Web PHP chinois (www.php.cn) !


Étiquettes associées:
source:php.cn
Déclaration de ce site Web
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
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal