C# 7.3 - 초기화 식에서 변수 사용 가능(expression variables in initializers)
이번 글로써 C# 7.3 기능 명세에 나온,
Language Feature Status
; https://github.com/dotnet/roslyn/blob/master/docs/Language%20Feature%20Status.md
모든 내용을 다루게 됩니다.
C# 7.3 (1) - 개선된 문법 4개(Support == and != for tuples, Ref Reassignment, Constraints, Stackalloc initializers)
; https://www.sysnet.pe.kr/2/0/11552
C# 7.3 (2) - 개선된 메서드 선택 규칙 3가지(Improved overload candidates)
; https://www.sysnet.pe.kr/2/0/11553
C# 7.3 (3) - 자동 구현 속성에 특성 적용 가능(Attribute on backing field)
; https://www.sysnet.pe.kr/2/0/11554
C# 7.3 (4) - 사용자 정의 타입에 fixed 적용 가능(Custom fixed)
; https://www.sysnet.pe.kr/2/0/11555
C# 7.3 (5) - 구조체의 고정 크기를 갖는 fixed 배열 필드에 대한 직접 접근 가능(Indexing movable fixed buffers)
; https://www.sysnet.pe.kr/2/0/11556
C# 7.3 (6) - blittable 제네릭 제약(blittable)
; https://www.sysnet.pe.kr/2/0/11558
C# 7.3 (7) - 초기화 식에서 변수 사용 가능(expression variables in initializers)
; https://www.sysnet.pe.kr/2/0/11560
이 중에서 문서에 나오지 않는 것으로 "strongname"이 있는데 딱히 이렇다 할 부가적인 문서가 없어 현시점(2018-06-25)에서 다룰 수가 없습니다. 여기저기 흩어진 내용으로 볼 때 어셈블리에 대한 "강력한 형식 이름" 부여와 관련해 C# 컴파일러의 옵션이 추가되는 듯한데, 따라서 문법적인 변화와는 상관이 없는 것 같습니다. 결국 실질적인 변화로는 위의 7개 글에서 모두 다룬 것입니다.
자, 그럼 마지막 항목을 가볍게 다뤄볼까요? ^^ 아래의 코드는 속성, 필드 및 생성자의 초기화를 비롯해 LINQ 쿼리 절에서 식(expression)을 사용하고 있는 예제입니다.
// 코드 참조: https://github.com/dotnet/csharplang/issues/32
using System;
class UserType
{
// 속성 초기화에 식 사용 가능
int Number { get; set; } = int.TryParse("5", out int _) ? 0 : -1;
// 필드 초기화에 식 사용 가능
private readonly bool _field1 = int.TryParse("5", out _);
}
class Base
{
bool _isFive;
public Base(bool isFive)
{
_isFive = isFive;
}
}
class UserCtor : Base
{
// 생성자의 초기화 구문에 식 사용 가능
public UserCtor(string s) : base(int.TryParse("5", out _))
{
}
}
class Program
{
static void Main()
{
string[] strings = new string[] { "test", "is", "good" };
// LINQ 쿼리 내에 식 사용 가능
var query1 = from text in strings
where int.TryParse(text, out int _)
select text;
}
}
그런데, 위와 같은 식 안에서 변수를 사용하는 경우(expression variables)에는 컴파일 오류가 발생합니다.
using System;
class UserType
{
// 속성 초기화 시 변수 사용 불가능
// C# 7.2까지 컴파일 오류 - Error CS8200 Out variable and pattern variable declarations are not allowed within constructor initializers, field initializers, or property initializers.
int Number { get; set; } = int.TryParse("5", out int i) ? i : -1;
// 필드 초기화 시 변수 사용 불가능
// C# 7.2까지 컴파일 오류 - Error CS8200 Out variable and pattern variable declarations are not allowed within constructor initializers, field initializers, or property initializers.
private readonly int _field1 = int.TryParse("5", out int value) ? value : -1;
}
class Base
{
int _number;
public Base(int number)
{
_number = number;
}
}
class UserCtor : Base
{
// 생성자의 초기화 식에서 변수 사용 불가능
// C# 7.2까지 컴파일 오류 - Error CS8200 Out variable and pattern variable declarations are not allowed within constructor initializers, field initializers, or property initializers.
public UserCtor(string s) : base(int.TryParse("5", out int i) ? i : -1)
{
}
}
class Program
{
static void Main()
{
string[] strings = new string[] { "5", "6", "good" };
// LINQ Query 절에서 변수 사용 불가능
// C# 7.2까지 컴파일 오류 - Error CS8201 Out variable and pattern variable declarations are not allowed within a query clause.
{
var numbers = from text in strings
let t = (int.TryParse(text, out var v), v)
where t.Item1
select t.Item2;
foreach (var item in numbers)
{
Console.WriteLine(item);
}
}
}
}
그리고 이러한 제약이 C# 7.3부터 풀렸다고 합니다.
expression variables in initializers
; https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.3/expression-variables-in-initializers.md
We extend the features introduced in C# 7 to permit expressions containing expression variables (out variable declarations and declaration patterns) in field initializers, property initializers, ctor-initializers, and query clauses.
즉 다음의 4가지 구문에서,
- field initializers
- property initializers
- ctor-initializers
- query clauses
"out variable declarations and declaration patterns"의 사용이 가능해진 것입니다. 보니까, out 변수 말고도 "declaration patterns"도 사용 가능하다고 하는데요, 테스트는 다음과 같이 할 수 있습니다.
// 초기화 구문에서 패턴 매칭 시 변수 사용 불가능
// C# 7.2까지 컴파일 오류 - Error CS8200 Out variable and pattern variable declarations are not allowed within constructor initializers, field initializers, or property initializers.
int Number3 { get; set; } = 5 is int value ? value : 0;
// LINQ Query 절에서 패턴 매칭 시 변수 사용 불가능
// C# 7.2까지 컴파일 오류 - Error CS8201 Out variable and pattern variable declarations are not allowed within a query clause.
{
object[] list = new object[] { 5, 6, "good" };
var numbers =
from item in list
let t = item is int value ? (true, value) : (false, 0)
where t.Item1
select t.Item2;
foreach (var item in numbers)
{
Console.WriteLine(item);
}
}
물론, 위의 코드는 C# 7.3부터 정상적으로 컴파일이 됩니다.
(
첨부 파일은 이 글의 예제 코드를 포함합니다.)
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]