with expression - Neničivá mutace vytváří nový objekt s upravenými vlastnostmi
Výraz with
vytvoří kopii svého operandu se zadanými vlastnostmi a upravenými poli. Pomocí syntaxe inicializátoru objektů určíte, které členy se mají upravovat, a jejich nové hodnoty:
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 }
}
}
Levý operand výrazu with
může být záznamového typu . Levý operand výrazu with
může být také typu struktury nebo anonymního typu.
Výsledek výrazu with
má stejný typ běhu jako operand výrazu, jak ukazuje následující příklad:
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 }
}
}
V případě člena referenčního typu se při kopírování operandu zkopíruje pouze reference na instanci člena. Kopie i původní operand mají přístup ke stejné instanci typu odkazu. Následující příklad ukazuje toto chování:
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
}
}
Vlastní sémantika kopírování
Jakýkoli typ záznamové třídy má kopírovací konstruktor .
konstruktor kopírování je konstruktor s jedním parametrem obsahujícího typ záznamu. Zkopíruje stav svého argumentu do nové instance záznamu. Při vyhodnocení výrazu with
se zavolá konstruktor kopírování k vytvoření nové instance záznamu na základě původního záznamu. Potom se nová instance aktualizuje podle zadaných úprav. Ve výchozím nastavení je konstruktor kopírování implicitní, tj. kompilátor generovaný. Pokud potřebujete přizpůsobit sémantiku kopírování záznamu, explicitně deklarujte konstruktor kopírování s požadovaným chováním. Následující příklad aktualizuje předchozí příklad pomocí explicitního konstruktoru kopírování. Nové chování kopírování spočívá ve kopírování položek seznamu místo odkazu na seznam při kopírování záznamu:
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
}
}
Sémantika kopírování pro typy struktur se nedá přizpůsobit.
Specifikace jazyka C#
Další informace najdete v následujících částech záznamu návrhu funkce:
Viz také
- operátory a výrazy jazyka C#
- záznamů
- typy struktury