Favicon

With expression

Peponi11/20/20243m

C#
SyntaxExpressionwith

1. Introduction

with 식은 형식의 일부를 수정한 복사를 가능하게 한다.

public record Foo(bool X, int Y);
 
public static void Main()
{
    var foo = new Foo(true, 100);
    var bar = foo with { Y = 50 };
 
    Console.WriteLine(foo);
    Console.WriteLine(bar);
}
 
/* output:
Foo { X = True, Y = 100 }
Foo { X = True, Y = 50 }
*/

C# 10부터는 구조체, 익명 형식 또한 with 식을 사용할 수 있다.

Struct
public struct Foo
{
    public bool X;
    public int Y;
 
    public Foo(bool x, int y)
    {
        X = x;
        Y = y;
    }
 
    public override string ToString() => $"{X}, {Y}";
}
 
public static void Main()
{
    var foo = new Foo(true, 100);
    var bar = foo with { Y = 50 };
 
    Console.WriteLine(foo);
    Console.WriteLine(bar);
}
 
/* output:
True, 100
True, 50
*/
Tuple
public static void Main()
{
    var foo = (true, 100);
    var bar = foo with { Item1 = false, Item2 = 20 };
 
    Console.WriteLine(foo);
    Console.WriteLine(bar);
}
 
/* output:
(True, 100)
(False, 20)
*/
Anonymous type
public static void Main()
{
    var foo = new { X = true, Y = 100 };
    var bar = foo with { X = false, Y = 10 };
 
    Console.WriteLine(foo);
    Console.WriteLine(bar);
}
 
/* output:
{ X = True, Y = 100 }
{ X = False, Y = 10 }
*/

2. 참조 형식 멤버

참조 형식 멤버의 경우 with를 통한 복사 시 인스턴스의 참조만 복사되어 주의가 필요하다.

public record Foo(List<int> A, int B);
 
public static void Main()
{
    var foo = new Foo(new() { 1, 2, 3, 4, 5 }, 6);
    var bar = foo with { B = 10 };
    bar.A.Add(777);
 
    Console.WriteLine(string.Join(", ", foo.A));
    Console.WriteLine(string.Join(", ", bar.A));
}
 
/* output:
1, 2, 3, 4, 5, 777
1, 2, 3, 4, 5, 777
*/

record 형식의 경우 복사 생성자가 컴파일러에 의해 생성된다. with를 이용한 복사 시 복사 생성자 호출 후 수정 사항이 반영되는데, 복사 생성자를 직접 작성하여 동작을 변경할 수 있다.

public record Foo(List<int> A, int B)
{
    protected Foo(Foo origin)
    {
        Console.WriteLine("Copy constructor called");
 
        A = new(origin.A);
        B = origin.B;
    }
}
 
public static void Main()
{
    var foo = new Foo(new() { 1, 2, 3, 4, 5 }, 6);
    var bar = foo with { B = 10 };
    bar.A.Add(777);
 
    Console.WriteLine(string.Join(", ", foo.A));
    Console.WriteLine(string.Join(", ", bar.A));
}
 
/* output:
Copy constructor called
1, 2, 3, 4, 5
1, 2, 3, 4, 5, 777
*/

3. 참조 자료