Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Tip
Эта статья является частью раздела "Основы" для разработчиков , которые уже знают хотя бы один язык программирования и учат C#. Начните с обзора сопоставления шаблонов , если вы не знакомы с шаблонами.
Деконструкция присваивает отдельные части значения — его компоненты — нескольким переменным в одной операции. Компоненты кортежа — это его элементы, предоставляемые по позиции. Другой тип может предоставлять компоненты, определяя метод Deconstruct.
Позиционные записи, которые объявляют свои свойства в виде параметров конструктора, автоматически получают метод Deconstruct.
Деконструкция кортежей
Предположим, что метод возвращает кортеж с данными города. Каждый компонент можно читать по одному за раз:
var cityData = QueryCityData("New York City");
var city = cityData.City;
var population = cityData.Population;
var area = cityData.Area;
Деструктуризация присваивает эти компоненты за один шаг:
(string city, int population, double area) = QueryCityData("New York City");
Вы также можете позволить C# автоматически определять типы переменных:
var (city, population, area) = QueryCityData("New York City");
Деконструкция может смешивать существующие переменные, только что объявленные переменные и игнорируемые значения в одном назначении:
(city, var population, _) = QueryCityData("New York City");
Выберите форму, которая упрощает чтение кода. Одинарный var перед круглыми скобками часто является самой четкой подразумеваемой формой. Вы также можете смешивать явные типы и var внутри круглых скобок, но эта форма обычно сложнее сканировать. Если вам нужны только некоторые значения, используйте отбрасывания вместо пропуска позиций.
Игнорировать ненужные значения с отбрасыванием
Каждое создаваемое значение должно соответствовать позиции слева от присваивания. Если вам не нужна одна или несколько позиций, используйте _ для пропуска:
var (_, _, population1960, _, population2010) = QueryPopulationDataForYears(
"New York City", 1960, 2010);
Здесь кортеж возвращает имя города, два года и два значения популяции. Деконструкция сохраняет только значения генеральной совокупности, так как вычисление использует только эти компоненты.
Деконструировать пользовательские типы
Класс, структура или интерфейс может поддерживать деконструкцию путем объявления метода Deconstruct. Каждый компонент становится out параметром, который позволяет методу назначить значение обратно переменной вызывающего кода, не возвращая его. Так как каждый компонент возвращается через параметр out, сам метод возвращает void:
public void Deconstruct(out string firstName, out string middleName, out string lastName)
{
firstName = FirstName;
middleName = MiddleName;
lastName = LastName;
}
Затем можно деконструировать экземпляр напрямую:
var (firstName, middleName, lastName) = passenger;
Тип может предоставлять несколько Deconstruct перегрузок с разной арностью — числом out параметров, объявленных методом, поэтому вызывающие могут выбрать количество компонентов для получения:
public void Deconstruct(out string firstName, out string lastName)
{
firstName = FirstName;
lastName = LastName;
}
public void Deconstruct(out string firstName, out string middleName, out string lastName)
{
firstName = FirstName;
middleName = MiddleName;
lastName = LastName;
}
public void Deconstruct(out string firstName, out string lastName, out string city, out string state)
{
firstName = FirstName;
lastName = LastName;
city = City;
state = State;
}
Две перегрузки с одинаковым количеством out параметров неоднозначны. Компилятор сообщает об ошибке неоднозначного вызова, поэтому различайте перегрузки по арности, а не только по типам параметров.
Отбрасывания также работают с декомпозицией, определяемой пользователем. Дополнительные сведения об отбрасывании, как правило, см. в разделе Отбрасывание и шаблон отбрасывания:
var (firstName, _, city, _) = passenger;
Разобрать записи
Позиционный record тип или record struct объявляет свои свойства как параметры самого объявления типа, аналогично конструктору. Компилятор создает Deconstruct метод для вас с out параметрами, соответствующими этим позиционным параметрам:
var (city, highTempC, lowTempC) = forecast;
Только позиционные параметры участвуют в этой сгенерированной деконструкции. Дополнительные свойства, объявленные в другом месте записи, не добавляются автоматически.
Деконструируйте типы, которые вам не принадлежат
Если изменить тип нельзя, можно по-прежнему поддерживать деконструкцию путем написания метода расширения — статического метода, добавляющего метод Deconstruct к типу, которым вы не владеете, как если бы он был членом этого типа. После добавления метода любое значение Uri может использовать синтаксис деконструкции:
static class UriExtensions
{
public static void Deconstruct(this Uri uri, out string scheme, out string host, out int port)
{
scheme = uri.Scheme;
host = uri.Host;
port = uri.Port;
}
}
Одно и то же правило неоднозначности применяется здесь: два метода расширения Deconstruct с одинаковой арностью являются неоднозначными. Неоднозначность также может возникать между методом экземпляра Deconstruct и методом расширения той же арности. В любом случае компилятор сообщает об ошибке при неоднозначном вызове.
Встроенная деконструкция системных типов
Некоторые системные типы уже определяют Deconstruct метод, используя тот же механизм, который вы использовали бы для собственных типов. Например, System.Collections.Generic.KeyValuePair<TKey,TValue> поддерживает деконструкцию, что делает итерацию по словарю более лаконичной:
foreach (var (repo, commitCount) in repoCommitCounts)
{
Console.WriteLine($"{repo} had {commitCount:N0} commits in this snapshot.");
}
Деконструкция и сопоставление шаблонов
Метод Deconstruct также поддерживает позиционные шаблоны для этого типа. Позиционный шаблон проверяет и деконструирует значение за один шаг, используя тот же синтаксис со скобками, что и деконструкция: person is ("Alice", 30) соответствует Person, деконструированные компоненты которого равны этим значениям. Это отличается от шаблона свойств, который проверяет именованные свойства напрямую, например person is { Name: "Alice", Age: 30 }. Шаблоны свойств обычно более понятны для структур объектов, так как имена элементов объясняют тест. Позиционные сопоставления с образцом наиболее эффективны, когда порядок уже несет значение, например в кортежах или других небольших упорядоченных значениях.