Clasa System - Object și metodele sale
Toate clasele din .NET, inclusiv cele pe care le creăm noi înșine, precum și tipurile de bază, cum ar fi System.Int32, derivă implicit din clasa Object. Chiar dacă nu specificăm clasa Object ca bază, implicit clasa Object este în vârful ierarhiei moștenirii. Prin urmare, toate tipurile și clasele pot implementa metodele definite în clasa System.Object. Să analizăm aceste metode.
Metoda ToString
Metoda ToString servește pentru obținerea unei reprezentări textuale a obiectului respectiv. Pentru tipurile de bază, va afișa valoarea lor textuală:
int i = 5;
Console.WriteLine(i.ToString()); // va afișa numărul 5
double d = 3.5;
Console.WriteLine(d.ToString()); // va afișa numărul 3,5
Pentru clase, această metodă afișează numele complet al clasei cu specificarea spațiului de nume în care este definită. Putem suprascrie această metodă. Să vedem un exemplu:
Person person = new Person { Name = "Tom" };
Console.WriteLine(person.ToString()); // va afișa numele clasei Person
Clock clock = new Clock { Hours = 15, Minutes = 34, Seconds = 53 };
Console.WriteLine(clock.ToString()); // va afișa 15:34:53
class Clock
{
public int Hours { get; set; }
public int Minutes { get; set; }
public int Seconds { get; set; }
public override string ToString()
{
return $"{Hours}:{Minutes}:{Seconds}";
}
}
class Person
{
public string Name { get; set; } = "";
}
Pentru suprascrierea metodei ToString în clasa Clock, care reprezintă ceasuri, se folosește cuvântul cheie override (la fel ca în cazul suprascrierii metodelor virtuale sau abstracte). În acest caz, metoda ToString afișează în șir de caractere valorile proprietăților Hours, Minutes, Seconds.
Clasa Person nu suprascrie metoda ToString, astfel încât pentru această clasă se aplică implementarea standard a acestei metode, care afișează pur și simplu numele clasei.
De asemenea, putem utiliza ambele implementări:
Person tom = new Person { Name = "Tom" };
Console.WriteLine(tom.ToString()); // Tom
Person undefined = new Person();
Console.WriteLine(undefined.ToString()); // Person
class Person
{
public string Name { get; set; } = "";
public override string? ToString()
{
if (string.IsNullOrEmpty(Name))
return base.ToString();
return Name;
}
}
Deci, dacă proprietatea Name nu are o valoare, ea reprezintă un șir gol, atunci se întoarce implementarea de bază - numele clasei. Este de remarcat că implementarea de bază returnează nu doar un șir de caractere, ci un obiect string?
- adică poate fi un șir de caractere string sau valoarea null, care indică lipsa unei valori. În realitate, ca tip returnat pentru metodă putem folosi atât string, cât și string.
Dacă numele obiectului Person este setat, atunci se întoarce valoarea proprietății Name. Pentru verificarea existenței unei valori în șir se utilizează metoda String.IsNullOrEmpty().
Este de remarcat că diverse tehnologii din platforma .NET utilizează metoda ToString pentru diferite scopuri. În special, metoda Console.WriteLine() afișează implicit reprezentarea textuală a obiectului.
Prin urmare, dacă trebuie să afișăm reprezentarea textuală a obiectului în consolă, atunci la transmiterea obiectului în metoda Console.WriteLine nu este necesar să utilizăm metoda ToString - aceasta este apelată implicit:
Person person = new Person { Name = "Tom" };
Console.WriteLine(person); // Tom
Clock clock = new Clock { Hours = 15, Minutes = 34, Seconds = 53 };
Console.WriteLine(clock); // va afișa 15:34:53
Metoda GetHashCode
Metoda GetHashCode permite returnarea unei valori numerice corespunzătoare obiectului respectiv sau codului său hash. Prin intermediul acestei valori, de exemplu, putem compara obiecte. Putem defini diverse algoritme pentru generarea unei astfel de valori sau putem folosi implementarea tipului de bază:
class Person
{
public string Name { get; set; } = "";
public override int GetHashCode()
{
return Name.GetHashCode();
}
}
În acest caz, metoda GetHashCode returnează codul hash pentru valoarea proprietății Name. Adică două obiecte Person care au același nume vor returna același cod hash. Totuși, în realitate, algoritmul poate fi foarte variat.
Obținerea tipului obiectului și metoda GetType
Metoda GetType permite obținerea tipului obiectului respectiv:
Person person = new Person { Name = "Tom" };
Console.WriteLine(person.GetType()); // Person
Această metodă returnează un obiect Type, adică tipul obiectului.
Prin intermediul cuvântului cheie typeof obținem tipul clasei și îl comparăm cu tipul obiectului. Și dacă acest obiect reprezintă tipul Person, atunci executăm anumite acțiuni.
object person = new Person { Name = "Tom" };
if (person.GetType() == typeof(Person))
Console.WriteLine("Acesta este cu adevărat clasa Person");
Deoarece clasa Object este tipul de bază pentru toate clasele, putem atribui unei variabile de tip object un obiect de orice tip. Totuși, pentru această variabilă, metoda GetType va returna în continuare tipul obiectului la care face referire variabila. Adică, în acest caz, obiectul de tip Person.
Este de remarcat că verificarea tipului din exemplul de mai sus poate fi simplificată folosind operatorul is:
object person = new Person { Name = "Tom" };
if (person is Person)
Console.WriteLine("Acesta este cu adevărat clasa Person");
Spre deosebire de metodele ToString, Equals, GetHashCode, metoda GetType nu se suprascrie.
Metoda Equals
Metoda Equals permite compararea a două obiecte pentru egalitate. Ca parametru, primește un obiect pentru comparare sub formă de tip object și returnează true dacă ambele obiecte sunt egale:
public override bool Equals(object? obj) {......}
De exemplu, implementăm această metodă în clasa Person:
class Person
{
public string Name { get; set; } = "";
public override bool Equals(object? obj)
{
// dacă parametrul metodei reprezintă tipul Person
// atunci returnăm true dacă numele coincid
if (obj is Person person) return Name == person.Name;
return false;
}
// împreună cu metoda Equals ar trebui să implementăm metoda GetHashCode
public override int GetHashCode() => Name.GetHashCode();
}
Metoda Equals primește ca parametru un obiect de orice tip, pe care îl convertim ulterior la clasa curentă - clasa Person.
Dacă obiectul transmis reprezintă tipul Person, atunci returnăm rezultatul comparării numelor a două obiecte Person. Dacă obiectul reprezintă un alt tip, atunci returnăm false.
În acest caz, pentru exemplu se aplică un algoritm simplu de comparare, dar, dacă este necesar, implementarea metodei poate fi mai complexă, de exemplu, comparând mai multe proprietăți, dacă acestea există.
Este de remarcat că împreună cu metoda Equals ar trebui să implementăm metoda GetHashCode.
Aplicarea metodei:
var person1 = new Person { Name = "Tom" };
var person2 = new Person { Name = "Bob" };
var person3 = new Person { Name = "Tom" };
bool person1EqualsPerson2 = person1.Equals(person2); // false
bool person1EqualsPerson3 = person1.Equals(person3); // true
Console.WriteLine(person1EqualsPerson2); // false
Console.WriteLine(person1EqualsPerson3); // true
Și dacă trebuie să comparăm două obiecte complexe, ca în acest caz, este mai bine să folosim metoda Equals, decât operația standard ==.