День 1958. #ЧтоНовенького #CSharp13
Типы-Расширения
Начиная с C# 3, методы расширения позволяют добавлять методы к базовому типу, даже если вы не можете изменить его код. LINQ — пример набора методов расширения IEnumerable<T>. Методы расширения LINQ выглядят так, как если бы они были методами экземпляра базового типа.
C# 13 идёт дальше, добавляя типы-расширения. Это новая разновидность типов языка, которая предоставляет элементы расширения для базового типа. Расширение включает методы, свойства и другие члены, которые могут быть как экземплярными, так и статическими. Типы-расширения экземпляра не могут хранить состояние, например, не могут включать экземплярные поля, но могут получать доступ к состоянию базового типа.
Виды
1. Неявные
Применяются ко всем экземплярам базового типа так же, как методы расширения.
2. Явные
Применяются только к экземплярам базового типа, которые были преобразованы в тип явного расширения (по аналогии с явной реализацией интерфейсов).
Пусть у нас есть базовые типы и нет доступа к изменению их кода:
public class Person()
{
public string FirstName { get; init; }
public string LastName { get; init; }
public Company Company { get; init; }
}
public class Company()
{
public string Name { get; init; }
public List<Team> Teams { get; init; }
}
public class Team()
{
public string TeamName { get; init; }
public Person Lead { get; init; }
public IEnumerable<Person> Members { get; init; }
}
Небольшой код LINQ поможет определить, является ли человек лидом. Но мы не хотим писать его каждый раз, поэтому можно написать метод расширения и контролировать доступ к нему через пространства имён. Или можно использовать неявный тип-расширение и предоставить свойство IsLead всем экземплярам Person:
public implicit extension PersonExtension for Person
{
public bool IsLead
=> this.Company
.Teams
.Any(team => team.Lead == this);
}
// Использование
if (person.IsLead) { … }
Явные расширения позволяют предоставлять дополнительные возможности конкретным экземплярам типа. Например, чтобы узнать, какие команды возглавляет человек, явное расширение может предоставлять свойство Teams только лидам (через приведение экземпляра Person к типу Lead):
public explicit extension Lead for Person
{
public IEnumerable<Team> Teams
=> this.Company
.Teams
.Where(team => team.Lead == this);
}
Как неявные, так и явные типы-расширения поддерживают и статические, и экземплярные члены. Вариант использования статических членов — предоставить значения по умолчанию, специфичные для вашего сценария. В данном случае у нас одна компания, и указывать её каждый раз при создании человека неудобно:
public implicit extension CompanyExtension for Company
{
private static Company company
= new Company("C# Design");
public static Person CreatePerson(
string firstName, string lastName)
=> new(firstName, lastName, company);
}
// Использование
var person = Company
.CreatePerson("Jon", "Smith");
// … добавляем ещё людей и команды
if (person.IsLead)
{
Lead lead = person;
PrintReport(lead.Teams);
}
С точки зрения использования типы-расширения позволяют упростить код, обеспечивающий важную работу и логику приложения, настраивая конкретные экземпляры базовых объектов под ваши нужды. С технической точки зрения типы-расширения представляют собой усовершенствование методов расширения, которые вы используете сегодня.
Источник: https://devblogs.microsoft.com/dotnet/dotnet-build-2024-announcements/
>>Click here to continue<<