Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować się zalogować lub zmienić katalog.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Wyrażenie — mutacja
Wyrażenie with tworzy kopię operandu z zmodyfikowanymi określonymi właściwościami i polami. Użyj składni inicjatora obiektów , aby określić, które elementy członkowskie mają być modyfikowane i ich nowe wartości:
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 }
}
}
Lewy operand wyrażenia może być typem rekorduwith. Może to być również typ struktury lub typ anonimowy.
Dokumentacja języka C# zawiera ostatnio wydaną wersję języka C#. Zawiera również początkową dokumentację dla funkcjonalności w publicznych wersjach testowych nadchodzącego wydania języka.
Dokumentacja identyfikuje dowolną funkcję po raz pierwszy wprowadzoną w ostatnich trzech wersjach języka lub w bieżącej publicznej wersji zapoznawczej.
Wskazówka
Aby dowiedzieć się, kiedy funkcja została po raz pierwszy wprowadzona w języku C#, zapoznaj się z artykułem dotyczącym historii wersji języka C#.
Wynik wyrażenia with ma ten sam typ czasu wykonywania co operand wyrażenia, jak pokazano w poniższym przykładzie:
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 }
}
}
Gdy element członkowski jest typem odwołania, kopiowanie tego elementu członkowskiego kopiuje tylko odwołanie do tego wystąpienia elementu członkowskiego. Zarówno kopia, jak i oryginalny operand uzyskują dostęp do tego samego wystąpienia typu odwołania. Na poniższym przykładzie zobrazowano to zachowanie.
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
}
}
Semantyka kopiowania niestandardowego
Każdy typ klasy rekordu ma konstruktor kopiujący. Konstruktor kopiujący jest konstruktorem z pojedynczym parametrem typu zawierającego rekord. Kopiuje stan argumentu do nowego wystąpienia rekordu. Podczas oceniania with wyrażenia wywołuje konstruktor kopiujący, aby utworzyć nowe wystąpienie rekordu na podstawie oryginalnego rekordu. Następnie aktualizuje nowe wystąpienie przy użyciu określonych modyfikacji. Domyślnie kompilator syntetyzuje konstruktor kopiujący. Aby dostosować semantyka kopiowania rekordów, jawnie zadeklaruj konstruktor kopii z żądanym zachowaniem. Poniższy przykład aktualizuje poprzedni przykład za pomocą jawnego konstruktora kopiowania. Nowe zachowanie kopiowania kopiuje elementy listy zamiast odwołania do listy po skopiowaniu rekordu:
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
}
}
Nie można dostosować semantyki kopiowania dla typów struktur.
Ważne
W poprzednich przykładach wszystkie właściwości są niezależne. Żadna z właściwości nie jest obliczana z innych wartości właściwości. Wyrażenie with najpierw kopiuje istniejące wystąpienie rekordu, a następnie modyfikuje wszystkie właściwości lub pola określone w wyrażeniu with . Obliczone właściwości w record typach powinny być obliczane na podstawie dostępu, a nie inicjowane podczas tworzenia wystąpienia. W przeciwnym razie właściwość może zwrócić obliczoną wartość na podstawie oryginalnego wystąpienia, a nie zmodyfikowanej kopii. Aby uzyskać więcej informacji, zobacz artykuł referencyjny języka dotyczący record typów.
Specyfikacja języka C#
Aby uzyskać więcej informacji, zapoznaj się z następującymi sekcjami propozycji funkcji zapisanych w notatce dotyczącej:
Zobacz też
- operatory i wyrażenia języka C#
- rekordy
- typy struktury