Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Выбор подходящего типа включает в себя рассмотрение его удобства использования, производительности и компромиссов по сравнению с другими типами. Анонимные типы были доступны с версии C# 3.0, а универсальные System.Tuple<T1,T2> типы появились с .NET Framework 4.0. С тех пор были введены новые опции с поддержкой на уровне языка, такие как System.ValueTuple<T1,T2> — как подразумевает его название, предоставляет тип значения с гибкостью анонимных типов. В этой статье вы узнаете, когда нужно выбрать один тип над другим.
Удобство использования и функциональные возможности
Анонимные типы появились в C# 3.0 с выражениями Language-Integrated Query (LINQ). С помощью LINQ разработчики часто проектируют результаты из запросов в анонимные типы, которые содержат несколько свойств из объектов, с которыми они работают. Рассмотрим следующий пример, который создает экземпляр массива из объектов DateTime и выполняет итерацию по ним, проецируя их в анонимный тип с двумя свойствами.
var dates = new[]
{
DateTime.UtcNow.AddHours(-1),
DateTime.UtcNow,
DateTime.UtcNow.AddHours(1),
};
foreach (var anonymous in
dates.Select(
date => new { Formatted = $"{date:MMM dd, yyyy hh:mm zzz}", date.Ticks }))
{
Console.WriteLine($"Ticks: {anonymous.Ticks}, formatted: {anonymous.Formatted}");
}
Анонимные типы создаются с помощью new оператора, а имена и типы свойств выводятся из объявления. Если два или более анонимных инициализаторов объектов в одной сборке указывают последовательность свойств, которые находятся в одном порядке и имеют одинаковые имена и типы, компилятор обрабатывает объекты как экземпляры одного типа. Они используют одни и те же сведения типа, созданные компилятором.
Предыдущий фрагмент кода C# проектируется анонимным типом с двумя свойствами, как и следующий класс C#, созданный компилятором:
internal sealed class f__AnonymousType0
{
public string Formatted { get; }
public long Ticks { get; }
public f__AnonymousType0(string formatted, long ticks)
{
Formatted = formatted;
Ticks = ticks;
}
}
Дополнительные сведения см. в анонимных типах. Та же функциональность доступна с кортежами при проецировании в запросы LINQ, и можно выбрать свойства в кортежи. Эти кортежи проходят через запрос так же, как и анонимные типы. Теперь рассмотрим следующий пример с помощью System.Tuple<string, long>.
var dates = new[]
{
DateTime.UtcNow.AddHours(-1),
DateTime.UtcNow,
DateTime.UtcNow.AddHours(1),
};
foreach (var tuple in
dates.Select(
date => new Tuple<string, long>($"{date:MMM dd, yyyy hh:mm zzz}", date.Ticks)))
{
Console.WriteLine($"Ticks: {tuple.Item2}, formatted: {tuple.Item1}");
}
System.Tuple<T1,T2> Экземпляр предоставляет нумерованные свойства элементa, такие как Item1 и Item2. Эти названия свойств могут затруднить понимание намерения значений свойств, поскольку название свойства предоставляет только порядковый номер. Кроме того, System.Tuple типы являются ссылочными class типами. Однако System.ValueTuple<T1,T2> является значимым типом struct. Следующий фрагмент кода C# использует ValueTuple<string, long> для проекции в заданный контекст. Таким образом, оно назначает с использованием литерального синтаксиса.
var dates = new[]
{
DateTime.UtcNow.AddHours(-1),
DateTime.UtcNow,
DateTime.UtcNow.AddHours(1),
};
foreach (var (formatted, ticks) in
dates.Select(
date => (Formatted: $"{date:MMM dd, yyyy at hh:mm zzz}", date.Ticks)))
{
Console.WriteLine($"Ticks: {ticks}, formatted: {formatted}");
}
Дополнительные сведения о кортежах см. в разделе Типы кортежей (справочник по C#) или Кортежи (Visual Basic).
В предыдущих примерах все функционально эквивалентны, однако существуют незначительные различия в их удобствах и их базовых реализациях.
Компромиссы
Возможно, вам стоит всегда предпочитать использование ValueTuple перед Tuple и анонимными типами, но следует учитывать компромиссы. ValueTuple Типы изменяются, в то время как Tuple доступны только для чтения. Анонимные типы можно использовать в деревьях выражений, в то время как кортежи не могут. В следующей таблице представлен обзор некоторых ключевых различий.
Основные отличия
| Имя | Модификатор доступа | Тип | Имя настраиваемого члена | Поддержка деконструкции | Поддержка дерева выражений |
|---|---|---|---|---|---|
| Анонимные типы | internal |
class |
✔️ | ❌ | ✔️ |
| Tuple | public |
class |
❌ | ❌ | ✔️ |
| ValueTuple | public |
struct |
✔️ | ✔️ | ❌ |
Сериализация
Одним из важных соображений при выборе типа является необходимость сериализации. Сериализация — это процесс преобразования состояния объекта в форму, которую можно сохранить или перенести. Дополнительные сведения см. в разделе сериализации. Предпочтителен выбор class или struct, чем использование анонимных типов или типов кортежей, когда важна сериализация.
Производительность
Производительность между этими типами зависит от сценария. Основное влияние связано с компромиссом между выделением ресурсов и копированием. В большинстве случаев влияние невелико. При возникновении серьезных последствий необходимо принять меры для информирования о решении.
Заключение
Разработчику, выбирая между кортежами и анонимными типами, следует учитывать несколько факторов. Как правило, если вы не работаете с деревьями выражений, и вам удобно использовать синтаксис кортежей, тогда выберите ValueTuple, так как они предоставляют тип значения с гибкостью для именования свойств. Если вы работаете с деревьями выражений, и вы предпочитаете именовать свойства, выберите анонимные типы. В противном случае используйте Tuple.