Pattern pentru proprietăți
Pattern pentru proprietăți permite compararea cu valorile anumitor proprietăți ale unui obiect. De exemplu, să presupunem că avem următoarea clasă:
class Person
{
public string Name { get; set; } = ""; // numele utilizatorului
public string Status { get; set; } = ""; // statutul utilizatorului
public string Language { get; set; } = ""; // limba utilizatorului
}
De exemplu, în funcție de limba utilizatorului, vom afișa un mesaj specific folosind pattern pentru proprietăți:
Person tom = new Person { Language = "english", Status = "user", Name = "Tom" };
Person pierre = new Person { Language = "french", Status = "user", Name = "Pierre" };
SayHello(tom); // Hello
SayHello(pierre); // Salut
void SayHello(Person person)
{
if (person is Person { Language: "french" })
{
Console.WriteLine("Salut");
}
else
{
Console.WriteLine("Hello");
}
}
Aici, metoda SayHello primește ca parametru un obiect de tip Person și îl compară cu un anumit pattern. Patternul este reprezentat de expresia Person { Language: "french" }. Adică, parametrul person trebuie să fie un obiect de tip Person al cărui proprietate Language este egală cu "french".
Putem folosi și un set de proprietăți. De exemplu, adăugăm verificarea pentru proprietatea Status:
Person tom = new Person { Language = "english", Status = "user", Name = "Tom" };
Person pierre = new Person { Language = "french", Status = "user", Name = "Pierre" };
Person admin = new Person { Language = "english", Status = "admin", Name = "Admin" };
SayHello(admin); // Hello, admin
SayHello(tom); // Hello
SayHello(pierre); // Salut
void SayHello(Person person)
{
if (person is Person { Language: "english", Status: "admin" })
{
Console.WriteLine("Hello, admin");
}
else if (person is Person { Language: "french" })
{
Console.WriteLine("Salut");
}
else
{
Console.WriteLine("Hello");
}
}
Acum, expresia if verifică dacă parametrul person este un obiect de tip Person al cărui proprietăți Language și Status au anumite valori.
De asemenea, putem folosi pattern matching pentru proprietăți în construcția switch:
string GetMessage(Person? p) => p switch
{
{ Language: "english" } => "Hello!",
{ Language: "german", Status: "admin" } => "Hallo, admin!",
{ Language: "french" } => "Salut!",
{ } => "undefined",
null => "null" // dacă Person p = null
};
Patternurile pentru proprietăți presupun folosirea acoladelor, în interiorul cărora sunt specificate proprietățile și valorile acestora: { proprietate: valoare }. Proprietățile obiectului transmis sunt comparate cu valorile din acolade.
Putem specifica mai multe proprietăți și valori în acolade: { Language: "german", Status: "admin" }, iar proprietățile obiectului transmis trebuie să corespundă tuturor acestor valori.
Putem lăsa acoladele goale, cum este cazul { } => "undefined" - obiectul transmis va corespunde acoladelor goale dacă nu corespunde nici unei valori anterioare sau dacă proprietățile sale nu sunt specificate sau au valoarea null.
Aplicare:
Person pierre = new Person { Language = "french", Status = "user", Name = "Pierre" };
string message = GetMessage(pierre);
Console.WriteLine(message); // Salut!
Person tomas = new Person { Language = "german", Status = "admin", Name = "Tomas" };
Console.WriteLine(GetMessage(tomas)); // Hallo, admin!
Person pablo = new Person { Language = "spanish", Status = "user", Name = "Pablo" };
Console.WriteLine(GetMessage(pablo)); // undefined
Console.WriteLine(GetMessage(null)); // null
În plus, putem defini variabile în pattern-urile pentru proprietăți, să le atribuim valori din obiect și să le folosim la returnarea valorii:
string GetMessage(Person? p) => p switch
{
{ Language: "german", Status: "admin" } => "Hallo, admin!",
{ Language: "french", Name: var name } => $"Salut, {name}!",
{ Language: var lang } => $"Unknown language: {lang}",
null => "null"
};
Astfel, sub-expresia Name: var name spune că trebuie să atribuim variabilei name valoarea proprietății Name. Apoi, o putem folosi la generarea valorii de ieșire: => $"Salut, {name}!"
Aplicare:
Person pierre = new Person { Language = "french", Status = "user", Name = "Pierre" };
string message = GetMessage(pierre);
Console.WriteLine(message); // Salut, Pierre!
Person tomas = new Person { Language = "german", Status = "admin", Name = "Tomas" };
Console.WriteLine(GetMessage(tomas)); // Hallo, admin!
Person pablo = new Person { Language = "spanish", Status = "user", Name = "Pablo" };
Console.WriteLine(GetMessage(pablo)); // Unknown language: spanish
Person? bob = null;
Console.WriteLine(GetMessage(bob)); // null
Începând cu versiunea C# 10, a fost simplificată potrivirea cu proprietățile obiectelor imbricate. Să presupunem că avem următoarele clase:
class Employee
{
public string Name { get; }
public Company Company { get; set; }
public Employee(string name, Company company)
{
Name = name;
Company = company;
}
}
class Company
{
public string Title { get; }
public Company(string title) => Title = title;
}
Clasa Company definește proprietatea Title, care stochează denumirea companiei. Clasa Employee definește un angajat al companiei și stochează compania în proprietatea Company. Aplicăm pattern matching pentru proprietăți pe baza proprietăților obiectului imbricat Company:
var microsoft = new Company("Microsoft");
var google = new Company("Google");
var tom = new Employee("Tom", microsoft);
var bob = new Employee("Bob", google);
PrintCompany(tom); // Tom works in Microsoft
PrintCompany(bob); // Bob works somewhere
void PrintCompany(Employee employee)
{
if (employee is Employee { Company: { Title: "Microsoft" } })
{
Console.WriteLine($"{employee.Name} works in Microsoft");
}
else
{
Console.WriteLine($"{employee.Name} works somewhere");
}
}
În metoda PrintCompany, obiectul employee este comparat cu patternul Employee { Company: { Title: "Microsoft" } }. Adică, angajatul trebuie să fie un obiect Employee al cărui companie are titlul "Microsoft".
Putem simplifica acest pattern astfel:
void PrintCompany(Employee employee)
{
if (employee is Employee { Company.Title: "Microsoft" })
{
Console.WriteLine($"{employee.Name} works in Microsoft");
}
else
{
Console.WriteLine($"{employee.Name} works somewhere");
}
}