Maison développement back-end Tutoriel C#.Net 3 réflexions sur la référence C# en détail

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

Mar 04, 2017 am 10:53 AM

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) !


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

Outils d'IA chauds

Undresser.AI Undress

Undresser.AI Undress

Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover

AI Clothes Remover

Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

AI Hentai Generator

AI Hentai Generator

Générez AI Hentai gratuitement.

Outils chauds

Bloc-notes++7.3.1

Bloc-notes++7.3.1

Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Active Directory avec C# Active Directory avec C# Sep 03, 2024 pm 03:33 PM

Guide d'Active Directory avec C#. Nous discutons ici de l'introduction et du fonctionnement d'Active Directory en C# ainsi que de la syntaxe et de l'exemple.

Sérialisation C# Sérialisation C# Sep 03, 2024 pm 03:30 PM

Guide de sérialisation C#. Nous discutons ici de l'introduction, des étapes de l'objet de sérialisation C#, du fonctionnement et de l'exemple respectivement.

Générateur de nombres aléatoires en C# Générateur de nombres aléatoires en C# Sep 03, 2024 pm 03:34 PM

Guide du générateur de nombres aléatoires en C#. Nous discutons ici du fonctionnement du générateur de nombres aléatoires, du concept de nombres pseudo-aléatoires et sécurisés.

Vue Grille de données C# Vue Grille de données C# Sep 03, 2024 pm 03:32 PM

Guide de la vue Grille de données C#. Nous discutons ici des exemples de la façon dont une vue de grille de données peut être chargée et exportée à partir de la base de données SQL ou d'un fichier Excel.

Modèles en C# Modèles en C# Sep 03, 2024 pm 03:33 PM

Guide des modèles en C#. Nous discutons ici de l'introduction et des 3 principaux types de modèles en C# ainsi que de ses exemples et de l'implémentation du code.

Nombres premiers en C# Nombres premiers en C# Sep 03, 2024 pm 03:35 PM

Guide des nombres premiers en C#. Nous discutons ici de l'introduction et des exemples de nombres premiers en c# ainsi que de l'implémentation du code.

Factorielle en C# Factorielle en C# Sep 03, 2024 pm 03:34 PM

Guide de Factorial en C#. Nous discutons ici de l'introduction de factorial en c# ainsi que de différents exemples et de l'implémentation du code.

La différence entre le multithreading et le C # asynchrone La différence entre le multithreading et le C # asynchrone Apr 03, 2025 pm 02:57 PM

La différence entre le multithreading et l'asynchrone est que le multithreading exécute plusieurs threads en même temps, tandis que les opérations effectuent de manière asynchrone sans bloquer le thread actuel. Le multithreading est utilisé pour les tâches à forte intensité de calcul, tandis que de manière asynchrone est utilisée pour l'interaction utilisateur. L'avantage du multi-threading est d'améliorer les performances informatiques, tandis que l'avantage des asynchrones est de ne pas bloquer les threads d'interface utilisateur. Le choix du multithreading ou asynchrone dépend de la nature de la tâche: les tâches à forte intensité de calcul utilisent le multithreading, les tâches qui interagissent avec les ressources externes et doivent maintenir la réactivité de l'interface utilisateur à utiliser asynchrone.

See all articles