Ескертпе
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Жүйеге кіруді немесе каталогтарды өзгертуді байқап көруге болады.
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Каталогтарды өзгертуді байқап көруге болады.
Выражение 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#
Дополнительную информацию см. в следующих разделах заметки о предложении функции записей :