Risipa de key_press | Programare

Programare .Net | Tehnici de programare | Tutoriale | Lectii si exemple

Risipa de key_press | Programare - Programare .Net | Tehnici de programare | Tutoriale | Lectii si exemple

Egalitate in C#

Egalitatea, din punct de vedere matematic, are urmatoarele proprietati: reflexivitate – un obiect este egal cu el insusi – (a=a), simetrie – ordinea nu conteaza – (a=b, b=a), tranzitivitate (a=b, b=c, a=c),

In C# exista doua tipuri de egalitate: egalitatea pentru referinta si egalitate pentru valoare.

Metoda Object.Equals determina daca doua variabile sunt egale. Pentru tipurile referinta vom introduce notiunea de object identity, iar pentru tipurile valoare vom suprascrie metoda la verificarea tipurilor si a continutului variabilelor.

Egalitatea pentru valoare

Egalitatea pentru valoare: cand doua obiecte sunt de acelasi tip si contin aceeasi valoare. De exemplu, doua variabile Integer au valoarea 10.

O prima modalitate de a verifica egalitatea pentru valoare este metoda Equals(Object objA, Object objB).

            Object o1 = 10;
            Object o2 = 10;
            //true
            Console.WriteLine(Object.Equals(o1, o2));

O a doua modalitate este Equals(Object obj):

            Object o1 = 10;
            Object o2 = 10;
            //true
            Console.WriteLine(o1.Equals(o2));

Egalitatea pentru referinta

Egalitatea pentru referinta se foloseste pentru a verifica daca doua obiecte de tip referinta indica spre acelasi obiect, numit object identify.

Construim clasa Employee.

    /// <summary>
    /// class Employee 
    /// </summary>
    class Employee 
    {

        private string _firstName;
        private string _lastName;
        private int _age;

        public string FirstName
        {
            get { return _firstName; }
            set { _firstName = value; }
        }

        public string LastName
        {
            get { return _lastName; }
            set { _lastName = value; }
        }

        public int Age
        {
            get { return _age; }
            set { _age = value; }
        }
    }

Cu ajutorul metodei ReferenceEquals vom verifica daca instantele specificate ca parametri reprezinta aceeasi instanta.

            Employee e1 = new Employee { FirstName = "George", LastName = "Georgescu", Age = 25 };
            Employee e2 = new Employee { FirstName = "George", LastName = "Georgescu", Age = 25 };

            //false
            Console.WriteLine(Object.ReferenceEquals(e1, e2));

Daca e2 va fi atribuit e1, atunci ReferenceEquals va returna true.

            e2 = e1;
            //true
            Console.WriteLine(Object.ReferenceEquals(e1, e2));

Daca doua obiecte sunt egale prin referinta, ele vor fi egale si prin valoare. Invers nu este valabil.

Metoda ReferenceEquals testeaza doar identitatea obiectului. Daca obiectele nu sunt de tip referinta, metoda va returna false.

            int i = 10;
            int j = 10;
            //false
            Console.WriteLine(Object.ReferenceEquals(i, j));

Operatorul ==

Pentru testarea egalitatii se foloseste si operatorul ==. Pentru tipurile valoare el va returna true daca operanzii au aceeasi valoare, altfel false.

            int i = 10;
            int j = 10;
            //true
            Console.WriteLine(i == j);

Pentru tipurile referinta el va returna true daca operanzii indica aceeasi referinta. Altfel, false.

            Employee e1 = new Employee { FirstName = "George", LastName = "Georgescu", Age = 25 };
            Employee e2 = new Employee { FirstName = "George", LastName = "Georgescu", Age = 25 };
            //false
            Console.WriteLine(e1 == e2);

Un caz special il reprezinta String, care este de tip referinta. In cazul acesta, operatorul == este definit sa compare valorile obiectelor String, nu referintele.

            string a = "marius";
            string b = "marius";
            //true, au aceeasi referinta
            Console.WriteLine(object.ReferenceEquals(a, b));
            //true, au aceeasi valoare
            Console.WriteLine(a == b);

            string c = String.Copy(a);
            //false, nu au aceeasi referinta
            Console.WriteLine(object.ReferenceEquals(a,c));
            //true, au aceeasi valoare
            Console.WriteLine(a==c);

Operatorul == se poate suprascrie.

IEquatable<T>

Dupa cum ati observat, metoda Equals accepta ca parametru un Object. Acest lucru inseamna ca vom pierde din flexibilitatea type-safe in cazul tipurilor referinta si ne vom “lovi” de boxing si unboxing pentru tipurile valoare. In .Net Framework 2.0 este introdusa interfata generica IEquatable pentru a scapa de aceste probleme.

Interfata are definita metoda Equals care va determina egalitatea instantelor tipului implementat.

    /// <summary>
    /// class Employee implements IEQuatable interface 
    /// </summary>
    class Employee : IEquatable<Employee>
    {

        private string _firstName;
        private string _lastName;
        private int _age;
        private decimal _wage;

        public string FirstName
        {
            get { return _firstName; }
            set { _firstName = value; }
        }

        public string LastName
        {
            get { return _lastName; }
            set { _lastName = value; }
        }

        public int Age
        {
            get { return _age; }
            set { _age = value; }
        }

        public decimal Wage
        {
            get { return _wage; }
            set { _wage = value; }
        }

        #region implementation of IEquatble interface
        public bool Equals(Employee other)
        {
            if (Object.ReferenceEquals(null, other)) return false;
            if (Object.ReferenceEquals(this, other)) return true;
            return Equals(other.FirstName, FirstName) && other.Age == Age && other.Wage == Wage && other.LastName == LastName;
        }
        #endregion
    }

            Employee e1 = new Employee { FirstName = "George", LastName = "Georgescu", Age = 25 };
            Employee e2 = new Employee { FirstName = "George", LastName = "Georgescu", Age = 25 };
            //true
            Console.WriteLine(e1.Equals(e2));
            //false
            Console.WriteLine(Object.ReferenceEquals(e1, e2));

In cazul implementarii acestei interfete se recomanda suprascrierea metodei Object.Equals(Object) pentru ca la executie va fi folosita metoda IEQuatable.Equals doar daca tipul obiectului transmis ca parametrul este acelasi cu cel din implementarea interfetei. Altfel, se va apela metoda Object.Equals.

        public override bool Equals(object obj)
        {
    
            if (Object.ReferenceEquals(obj, null))
                return false;
            if (Object.ReferenceEquals(this, obj))
                return true;
            if (this.GetType() != obj.GetType())
                return false;

            return this.Equals(obj as Employee);
      }

De asemenea, trebuie suprascrisa si metoda Object.GetHashCode. Daca nu suprascriem, vom primi un mesaj de atentionare in momentul compilarii. Acesta poate fi ignorat daca nu folosim obiectele in structuri/algoritmi de dispersie.

Doua obiecte care au acelasi tip sunt egale daca returneaza acelasi cod de dispersie.

C# ofera multe modalitati de testare a egalitatii. Se pot suprascrie, fara probleme, Equals si operatorul == pentru tipurile de tip valoare sau Equals pentru tipurile de tip referinta. Ori de cate ori se suprascrie metoda, se recomanda implementarea interfetei IEquatable.

Category: Uncategorized

Your email address will not be published. Required fields are marked *

*