Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Выражение with создает копию операнда с указанными свойствами и полями, измененными. Используйте синтаксис инициализатора объектов , чтобы указать, какие члены необходимо изменить и их новые значения:
using System;
public class WithExpressionBasicExample
{
public record NamedPoint(string Name, int X, int Y);
public static void Main()
{
var p1 = new NamedPoint("A", 0, 0);
Console.WriteLine($"{nameof(p1)}: {p1}"); // output: p1: NamedPoint { Name = A, X = 0, Y = 0 }
var p2 = p1 with { Name = "B", X = 5 };
Console.WriteLine($"{nameof(p2)}: {p2}"); // output: p2: NamedPoint { Name = B, X = 5, Y = 0 }
var p3 = p1 with
{
Name = "C",
Y = 4
};
Console.WriteLine($"{nameof(p3)}: {p3}"); // output: p3: NamedPoint { Name = C, X = 0, Y = 4 }
Console.WriteLine($"{nameof(p1)}: {p1}"); // output: p1: NamedPoint { Name = A, X = 0, Y = 0 }
var apples = new { Item = "Apples", Price = 1.19m };
Console.WriteLine($"Original: {apples}"); // output: Original: { Item = Apples, Price = 1.19 }
var saleApples = apples with { Price = 0.79m };
Console.WriteLine($"Sale: {saleApples}"); // output: Sale: { Item = Apples, Price = 0.79 }
}
}
Левый операнды with выражения может быть типом записи. Он также может быть типом структуры или анонимным типом.
Справочные документы по языку C# описывают последнюю выпущенную версию языка C#. Она также содержит начальную документацию по функциям в общедоступных предварительных версиях для предстоящего языкового выпуска.
Документация определяет любую функцию, впервые представленную в последних трех версиях языка или в текущих общедоступных предварительных версиях.
Подсказка
Чтобы узнать, когда функция впервые появилась в C#, ознакомьтесь со статьей об истории версий языка C#.
Результат выражения with имеет тот же тип времени выполнения, что и операнды выражения, как показано в следующем примере:
using System;
public class InheritanceExample
{
public record Point(int X, int Y);
public record NamedPoint(string Name, int X, int Y) : Point(X, Y);
public static void Main()
{
Point p1 = new NamedPoint("A", 0, 0);
Point p2 = p1 with { X = 5, Y = 3 };
Console.WriteLine(p2 is NamedPoint); // output: True
Console.WriteLine(p2); // output: NamedPoint { X = 5, Y = 3, Name = A }
}
}
Если элемент является ссылочным типом, копирование этого элемента копирует только ссылку на этот экземпляр элемента. Как копия, так и исходный операнды обращаются к одному экземпляру ссылочного типа. В следующем примере демонстрируется это поведение:
using System;
using System.Collections.Generic;
public class ExampleWithReferenceType
{
public record TaggedNumber(int Number, List<string> Tags)
{
public string PrintTags() => string.Join(", ", Tags);
}
public static void Main()
{
var original = new TaggedNumber(1, new List<string> { "A", "B" });
var copy = original with { Number = 2 };
Console.WriteLine($"Tags of {nameof(copy)}: {copy.PrintTags()}");
// output: Tags of copy: A, B
original.Tags.Add("C");
Console.WriteLine($"Tags of {nameof(copy)}: {copy.PrintTags()}");
// output: Tags of copy: A, B, C
}
}
Семантика настраиваемого копирования
Каждый тип класса записи имеет конструктор копирования. Конструктор копирования — это конструктор с одним параметром содержащего типа записи. Он копирует состояние аргумента в новый экземпляр записи. При вычислении with выражения он вызывает конструктор копирования для создания нового экземпляра записи на основе исходной записи. Затем он обновляет новый экземпляр с указанными изменениями. По умолчанию компилятор синтезирует конструктор копирования. Чтобы настроить семантику копирования записей, явно объявите конструктор копирования с требуемым поведением. Следующий пример обновляет предыдущий пример с явным конструктором копирования. Новое поведение копирования копирует элементы списка вместо ссылки на список при копировании записи:
using System;
using System.Collections.Generic;
public class UserDefinedCopyConstructorExample
{
public record TaggedNumber(int Number, List<string> Tags)
{
protected TaggedNumber(TaggedNumber original)
{
Number = original.Number;
Tags = new List<string>(original.Tags);
}
public string PrintTags() => string.Join(", ", Tags);
}
public static void Main()
{
var original = new TaggedNumber(1, new List<string> { "A", "B" });
var copy = original with { Number = 2 };
Console.WriteLine($"Tags of {nameof(copy)}: {copy.PrintTags()}");
// output: Tags of copy: A, B
original.Tags.Add("C");
Console.WriteLine($"Tags of {nameof(copy)}: {copy.PrintTags()}");
// output: Tags of copy: A, B
}
}
Невозможно настроить семантику копирования для типов структур.
Это важно
В предыдущих примерах все свойства являются независимыми. Ни один из свойств не вычисляется из других значений свойств.
with Выражение сначала копирует существующий экземпляр записи, а затем изменяет все свойства или поля, указанные with в выражении. Вычисляемые свойства в record типах должны вычисляться при доступе, а не инициализироваться при создании экземпляра. В противном случае свойство может возвращать вычисляемое значение на основе исходного экземпляра, а не измененной копии. Дополнительные сведения см. в справочной статье о языках типовrecord.
Спецификация языка C#
Дополнительную информацию см. в следующих разделах заметки о предложении функции записей :