C# 7.2에서 도입된 in 파라미터는 Value 타입의 파라미터를 Pass by reference로 전달할 수 있게 하는 기능을 제공한다. 만약 파라미터로 전달하는 구조체가(Value 타입) 큰 사이즈라면, Pass by value로 복사해서 전달하는 것보다 위치 정보만을 전달하는 Pass by reference를 사용하는 것이 성능면에서 효율적이다. 이러한 목적으로 in 파라미터는 구조체를 Pass by value로 전달할 수 있는 기능을 제공한다.
만약 구조체 전체가 readonly라면, 즉 구조체 내부의 모든 멤버가 readonly라면, in 파라미터를 사용하여 Pass by reference로 전달할 지라도 호출된 메서드(Callee)에서 구조체의 내부 상태를 변경하는 행위를 할 수 없으므로, 호출자(Caller)의 구조체는 변경되지 않을 것이 확실하다. 이러한 측면에 큰 사이즈의 구조체를 in 파라미터로 전달하기 위해, (가능하다면) 구조체를 readonly로 만들 것이 좋을 것이다. 하지만, 경우에 따라 구조체가 상태를 변경하는 멤버를 가질 수도 있다. 이러한 경우에는 일부 멤버들에 대해 readonly 멤버를 사용하는 것을 고려해 볼 수 있다.
Non-readonly 구조체인 경우 in 파라미터로 전달되면, 컴파일러는 호출된 메서드(Callee)에서 전달된 구조체의 멤버(메서드나 속성 등)을 호출할 때마다 구조체 파라미터를 복사하게 된다. 이는 컴파일러가 구조체의 멤버가 상태를 변경하는지 미리 알 수 없기 때문에, 방어적으로 구조체를 다시 복사(defensive copy or hidden copy)하여 사용하는 것이다. 구조체의 크기가 큰 경우 Callee 에서 그 구조체에 대해 10개의 메서드/속성을 호출한다면, 10번의 복사가 읽어나는데 이는 성능을 저하시키는 원인이 될 수 있다.
예제
{
public int a, b, c;
public Triangle(int a, int b, int c)
{
this.a = a;
this.b = b;
this.c = c;
}
public int Perimeter => a + b + c;
public bool IsEquilateral => a == b && b == c;
}
private void Check(in Triangle tri)
{
int perim = tri.Perimeter;
bool equi = tri.IsEquilateral;
Console.WriteLine($"{perim}, {equi}");
}
static void Main(string[] args)
{
Triangle t = new Triangle(3, 4, 5);
new Program().Check(t);
}
예제
{
Triangle triangle = tri;
int perimeter = triangle.Perimeter;
triangle = tri;
bool isEquilateral = triangle.IsEquilateral;
Console.WriteLine(string.Format("{0}, {1}", perimeter, isEquilateral));
}
예제
public readonly bool IsEquilateral => a == b && b == c;
예제
{
int perim = tri.Perimeter;
bool equi = tri.IsEquilateral;
Console.WriteLine($"{perim}, {equi}");
}