with 運算式:非破壞性變動會建立具有已修改屬性的新物件
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# 10 開始,with
運算式的左邊運算元也可以是結構型別或匿名型別。
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
}
}
您無法自訂結構型別的複製語意。
C# 語言規格
如需詳細資訊,請參閱記錄功能提案附註的下列各節: