[TIP] .Net 8 새로운 문법

기존에 Class 를 생성하고 Property를 생성하는 방법입니다.

public class ClassOld
{
    public string Name { get; set; }
    public int age { get; set; }
    public ClassOld(string _name , int _age)
    {
        Name = _name;
        age = _age;
    }
    public void Test1()
    {
        Console.WriteLine($"{Name} / {age}");
    }
}

대단히 익숙한 방법일것니다.

8.0에서는 이렇게 되는군요

public class ClassNew(string name, int age)
{
    public void Test1()
    {
        Console.WriteLine($"{name} / {age}");
    }
}

Class 선언부에서 Argument 먹이듯이 property 를 할당할수 있군요

당연히 차이없이 잘나오네요

image

개인적으로 별것이 다되는군요

Property 생성이 목적이라면

public class Test(string name, int age) { }

이렇게 한줄로도 가능하겠네요
개인적으로 Record 문법도 있긴한데 낯설어서 아직 property 를 만드는것이 익숙합니다.

아주 오래전에는

priavate string name ="";

pub string Name 
{
 get { return name ; }
set { name =value; }
}
이런시절도 있었는데요 
14 Likes

C# 12에 추가된 기본 생성자는 말씀하신 것 처럼 코드량을 줄이기 때문에 생성 인자를 꼭 받아야 할 때 유용합니다.

다만 설명하신 부분 중 record와 다르게 기본 생성자 인자는 외부에서 접근할 수 없어서 속성으로 바로 활용할 수 없어요.

public string Name => name;

외부로 공개하고자 할 경우 이렇게 사용해야 합니다.

7 Likes

아 생각해보니 그렇네요 Property 개념으로 접근하기 보다는 arguement 로 생각해야겠네요

4 Likes

di 로도 되겠네요 ㅎㅎ

4 Likes

Primary Constructor 라고 부릅니다.
일반적인 클래스 보다는
Dto나 record 문법을 활용한 클래스에 쓰면 굉장히 유용하더라구요

6 Likes

Primary constructor의 문제점

클래스 내부에서 파라메터(라고 읽고 필드)에 재할당 할 수 있어 무섭지요.

Primary constructor 최초 소개

굉장히 비난 받았었어요. (blog 댓글 참조)

Primary constructor에 readonly가 필요한 이유

100,000명보다 더 많은 개발자가 요구할거 같은데… 과연

6 Likes

기본 생성자는 두 가지 성질이 있는 것 같습니다.

  1. 항상 호출되어야 함.
  2. 생성자의 매개변수가 private 멤버 변수가 됨.

두 번째가 조금 성급한 결정 같아 보입니다.

readonly 가 붙어야 한다 말아야 한다는 논의도 중요하지만, 상태의 2중 저장에 대한 컴파일러 경고 문제도 있더군요.

예를 들면, 아래 코드에서 #1 코드는 #2 의 존재 여부에 따라 경고가 뜨기고 하고 안 뜨기도 합니다.

class C(int i)
{
    public C() : this(1) { }
    private readonly int _i = i; // #1
    public int Value() => i++; // #2
}

두 번째 가정만 없앤다면, 논란 없는 꿀 문법(Syntactic sugar)일 것이라고 생각합니다.

  1. 항상 호출되어야 함.
  2. 생성자의 매개변수의 유효범위는 멤버 초기화 시간 한정.
class C(int i)
{
    public C() : this(1) { }
    private readonly int _i = i; 
    public int Value() => _i + 1; 
    // 에러
    // public int Value() => i++; 
}
2 Likes

제가 잘못 이해한 것일 수도 있겠으나,
readonly 타입의 프로퍼티를 정의해서 DTO로 사용될 목적이면 괜찮을것 같긴 합니다.

추가
흠… 근데 가만 생각해보니 DTO로 사용된다 하더라도…

var result = new TestDTO(
"이건", "파라미터의", "연속", "중간에", null, "이 들어갈 수 있으니", "이렇게 길어질 수도 있으려나..");

var result = new TestDTO(foo: "아니면", bar: "이렇게 선언할까")

아래와 같은 접근은 불가능.

var result = new TestDTO();
result.Foo = "선택적인";
result.Bar = "할당 후 post";
3 Likes

네 그런것 같습니다 dto로 활용하기에는 노출이 안되는 field네요
readonly 값으로 써야할것 같습니다.
왠지 다음버전에서는
public class Test(public string a)
이렇게 접근 지정자도 되지 않을까요

4 Likes

오픈소스 보다가 발견해서 이게 말이 된다고?
싶어서 콘솔 프로젝트 만들고 해보니 에러 안떠서 놀란 1인입니다. :joy:

6 Likes

제가 확인한 바로는 record와 1:1로 대응되는 단순 프라이빗 맴버가 아니라
지역변수를 클로저로 캡쳐했을때의 상태에 가깝습니다.
기본생성자의 파라미터를 맴버초기화용으로만 사용한다면 이상적으로 코드만 짧아지고 끝이지만,
어느 함수에 포함하게되는순간 캡쳐된채로 힙메모리를 차지하고있어야 하는거죠.

record에서는 파라미터를 함수에서 사용하여도 맴버취급이지만,
델리게이트맴버를 초기화 하는데 사용한다면 똑같이 캡쳐가 발생할것입니다.

제생각엔 이러한것도 굳이 신경쓰지 않고 자유롭게 사용해도 별일 없을듯 하지만,
최적화와 변인통제를 고려했을때 불안요인으로 보이는건 사실이네요

+추가
이리저리 테스트해보니 마냥 캡쳐로만 볼수도 없고 케이스에 따라 막 바뀌네요 ㅡㅡ;

5 Likes

image

인텔리센스에 의지해 확인해보시면 하이라이팅부터 다른걸 알수있습니다.
기본생성자가지고 private member가 생기진 않습니다. 캡쳐일뿐이죠
흰색은 맴버에 반영된값을 접근한것이고 파란색은 캡쳐된 파라미터를 가져옵니다.

record에서의 경우에도 똑같이 자동생성된 맴버의 값과 캡쳐된 값이 같은이름일지라도 다른위치의 복사본입니다. 런타임에서 두 값이 통제되지않고 어떻게 다르게 바뀔지 모르는겁니다,

기본생성자로 인한 우려사항들은 어차피 record를 도입할 당시부터 내포한것들이기 때문에,
실제로 문제가 되건 안되건 사실상 소용이 없는 시점이 같습니다. 지금은

5 Likes

캡쳐라는 용어가 좀 낯설게 느껴집니다. 어떤 의미일까요?

다른 글에서는 컴파일러가 기본 생성자의 매개 변수를 필드(private member)로 등록한다고 설명하는데, 그것과 다른 무엇인가요?

2 Likes

C# Closure 이해하기 - C# 프로그래밍 배우기 (Learn C# Programming) (csharpstudy.com)

지역변수를 클로저 델리게이트에 포함시킬때 해당 지역변수를 캡쳐한다고 표현하는데요,

인스턴스 생성자 - C# | Microsoft Learn

저는 이 문서 보고 매개변수가 캡쳐되더라도 생성한 객체와 무관한 별도의 메모리위치에 자리잡는걸로 오해했었는데, 조건부로 객체에 포함되는방식이었네요,
확실한건, 마냥 등록하는건 아니고 생성시점 이외의 함수 등에 매개변수를 사용하지않았다면 굳이 필드에 등록되지 않습니다.

쓰기는 편한데 이해를 하려니 테스트를 해도 경우에따라 처리가 유연히 바뀌고 하니 어렵네요 ㅠ

2 Likes

아직 사용해 보지는 않았지만 이런 방법도 있군요.

Roslyn analyzer에 primary constructor parameter에 대한 readonly 규칙 추가하기

2 Likes

DI때문에 생겨난 개념 아닐까 합니다.
의존성 주입 클래스의 경우 생성자에서 각 프로퍼티/필드에 간단한 할당만 하는 경우가 대부분이었고
기존은 귀찮은 느낌이 들었던건 사실이었죠 ㅋㅋ; 생성자에서 인자 많이 받을수록 더더욱…

1 Like

잘 되는군요. 추천합니다. 클래스의 속성을 불변으로 다루면 장점이 매우 커서

1 Like