식은 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# 언어 사양
자세한 내용은 레코드 기능 제안 참고 사항의 다음 섹션을 참조하세요.
참고하십시오
.NET