https://devblogs.microsoft.com/dotnet/welcome-to-c-9-0/
아마 Build 2020 에서 발표된 내용인듯 하다.
C#9.0의 경우 아직 릴리즈전이지만 추가예정인 주요기능을 살펴보자
Init-Only Properties
public class Person
{
public string FirstName { get; init; }
public string LastName { get; init; }
}
set 위치에 init 을 사용하여 선언시에만 초기화를 시킬수 있다.
public class Person
{
private readonly string firstName;
private readonly string lastName;
public string FirstName
{
get => firstName;
init => firstName = (value ?? throw new ArgumentNullException(nameof(FirstName)));
}
public string LastName
{
get => lastName;
init => lastName = (value ?? throw new ArgumentNullException(nameof(LastName)));
}
}
auto properties 가 아닌경우 위와같이 사용할수있다.
Record
위의 Init only 가 개별속성을 후속 할당 불가능으로 만든다면 Record는 개체 전체가 후속 할당 불가능이다.
public data class Person
{
public string FirstName { get; init; }
public string LastName { get; init; }
}
data 키워드를 이용하여 Record로 만든다.
-> 정식에서는 data 대신 record 로 명칭이 변경되었다
With-expressions
불변데이터에서 일부만 변경된 개체를 만들때 변경된요소만 제외하고 하나씩 복사하는것은 힘들다.
with 표현을 사용하여 일부데이터만 변경된 새로운 불변데이터를 얻을수있다.
var otherPerson = person with { LastName = "Hanselman" };
Value-based equality
레코드를 Equals 로 비교하면 Value 기반으로 비교한다. (구조체처럼 동작한다.)
즉 모든 속성들이 같은 값이면 같은 레코드 취급한다.
불변 데이터이므로 어찌보면 당연하다.
Data members
public data class Person { string FirstName; string LastName; } //1
public data class Person //2
{
public string FirstName { get; init; }
public string LastName { get; init; }
}
1번 표현과 2번표현은 동일하다.
Record 의 모든 속성을 힘들게 init으로 처리할 필요가 없다.
Positional records
왜 positional 이라는 용어를 사용하는지는 모르겠지만 Destructing 이 가능하다.
public data class Person //1
{
string FirstName;
string LastName;
public Person(string firstName, string lastName)
=> (FirstName, LastName) = (firstName, lastName);
public void Deconstruct(out string firstName, out string lastName)
=> (firstName, lastName) = (FirstName, LastName);
}
public data class Person(string FirstName, string LastName); //2
1번 방식으로 구현해줄수있고
2번 방식으로 하면 자동으로 구현된다.
var person = new Person("Scott", "Hunter"); // positional construction
var (f, l) = person; // positional deconstruction
위와 같이 사용한다.
Records and mutation
제대로 해석한게 맞는지 모르겠는데 암튼 리코드는 Mutate 랑 안어울린다는 이야기인듯.
With-expressions and inheritance
public data class Person { string FirstName; string LastName; }
public data class Student : Person { int ID; }
Person person = new Student { FirstName = "Scott", LastName = "Hunter", ID = GetNewId() };
otherPerson = person with { LastName = "Hanselman" };
인경우 otherPerson 은 person 과 같이 Student 이며 ID는 동일하게 된다(GetNewID 로 새로운 ID를 할당받는것이 아님), C# Record의 Cloning 은 virtual 이라 자동적으로 파생클래스에서도 호출된다..?
을 뜻하는것 같은데 정확한 내용은 모르겠음. Mutate + 상속을 쓰지 말라는 의미인가..?
Value-based equality and inheritance
Person person1 = new Person { FirstName = "Scott", LastName = "Hunter" };
Person person2 = new Student { FirstName = "Scott", LastName = "Hunter", ID = GetNewId() };
위 와 비슷하게..
person1 입장 에서 person2는 같은 개체로 보일것이다. (자신이 가진 프로퍼티가 전부 같으므로)
근데 person2입장에서는 person1은 다른 개체이다.
따라서 두개는 Equals 하지않다.
C# Record 에서는 이를 자동적으로 Equals 하지않다고 판별해준다. (내부)
Top-level programs
using System;
class Program
{
static void Main()
{
Console.WriteLine("Hello World!");
}
}
를
using System;
Console.WriteLine("Hello World!");
처럼 코딩가능하다.
Improved pattern matching
패턴매칭이 더 좋아졌다.
public static decimal CalculateToll(object vehicle) =>
vehicle switch
{
...
DeliveryTruck t when t.GrossWeightClass > 5000 => 10.00m + 5.00m,
DeliveryTruck t when t.GrossWeightClass < 3000 => 10.00m - 2.00m,
DeliveryTruck _ => 10.00m,
_ => throw new ArgumentException("Not a known vehicle type", nameof(vehicle))
};
위는 8.0의 패턴 매칭이다.
DeliveryTruck => 10.00m,
_ 를 뺄수있다. (Simple type patterns)
DeliveryTruck t when t.GrossWeightClass switch
{
> 5000 => 10.00m + 5.00m,
< 3000 => 10.00m - 2.00m,
_ => 10.00m,
},
<, <= 과 같은 조건식을 패턴매치할수있다. 중첩 Switch 에서도 사용할수있다. (Relational patterns)
DeliveryTruck t when t.GrossWeightClass switch
{
< 3000 => 10.00m - 2.00m,
>= 3000 and <= 5000 => 10.00m,
> 5000 => 10.00m + 5.00m,
},
and,or 도 쓸수있다. (Logical patterns)
Improved target typing
Target-typed new expressions
Point p = new (3, 5);
new이후 타입명세 필요없음
Target typed ?? and ?:
Person person = student ?? customer; // Shared base type
int? result = b ? 0 : null; // nullable value type
?? 과 ?: 에서 같은 부모를가지는 타입 이지만 다른 파생클래스, nullable을 허용한다.
Covariant returns
abstract class Animal
{
public abstract Food GetFood();
...
}
class Tiger : Animal
{
public override Meat GetFood() => ...;
}
Meat 가 Food의 파생클래스일떄,
Food 가 리턴되는 함수에대한 공변셩을 가진다.
즉 위와같이 Animal 의 Food를 리턴하는 GetFood함수
Tiger(Animal 파생) 의 Meat(Food 파생) 을 리턴하는 함수로 오버라이딩이 가능하다.
'프로그래밍 언어 노트 > C#' 카테고리의 다른 글
[C#/WPF] ObservableCollection, List 간의 변환 (0) | 2020.06.03 |
---|---|
[C#] 공변성(Covariance)과 반 공변성(Contravariance ) (1) | 2020.05.23 |
[C#/Winform] ElementHost 를 이용하여 WinForm 에서 WPF 컨트롤 호스팅 (0) | 2020.05.14 |
[C#] C# 버전별 주요 변화 (0) | 2020.04.01 |
[C#] 닷넷의 기본 파일 처리함수는 부정확할 수 있다 (0) | 2020.02.25 |