속성이나 메서드의 Body 블럭이 간단한 경우에, Statement Block을 사용하는 대신 간단한 함수식 (expression)을 사용할 수 있다. 이를 표현식멤버라고 한다.
람다식과 유사하다.
public int Area{
get{
return Height * Width;
}
}
public int Area => Height * Width;
// 메서드에서 하나의 Point 개체 리턴
public Point Move(int x, int y) => new Point(X+x, Y+y);
// 메서드에서 void 리턴
public void Print() => Console.WriteLine(data);
// 속성에서 get 리턴
public string Name => FirstName + " " + LastName;
// 인덱서에서 Customer 개체 리턴
public Customer this[int id] => db.FindCustomer(id);
// 연산자 메서드 표현
public static Complex operator +(Complex a, Complex b) => a.Add(b);
이를 통해서 변경불가능 속성 (Immutable Property)를 간단하게 구현할 수 있게 되었다.
class Person{
public string Name { get; set; } = "No Name";
// 초기화를 하지 않았을 때는 default 값이 사용된다.
public string NickName { get; } // null
public int Age { get; } // 0
// Auto-Property Initializer 할당
public bool Enabled { get; } = true;
// 생성자에서 초기값 할당
public int Level{ get; }
public Person(){
this.Level = 1;
}
}
원래 속성을 작성할때 이렇게 하지 않는가?
class A{
public string Name{
private string _name = string.Empty;
get{ return _name; }
set{ this._name = value; }
}
}
이걸 갖다가
class A{
public string Name{
get;set;
} = string.Empty;
}
기존에 C# 5.0에서 await 기능을 도입할 때, catch나 finally 블록에서 await을 사용하는 기능을 지원하지 않았고, 개발자들은 여러 WorkAround를 사용했어야 했는데 C# 6.0부터 사용가능하게 되었다.
Catch 블럭에서 일반적으로 에러를 로깅을 하는 경우가 많은데, 이 때 로깅처리를 비동기적으로 하기 위해서 await을 사용할 수 있다.
IDbConnection conn;
try{
var response = await req.GetResponseAsync();
}
catch(Exception ex)
{
await Log(ex);
}
finally
{
await Close(conn);
}
Catch 시에 특정한 조건으로만 다시 필터링하여 Catch 하는 것으로 C# 6.0이후의 문법에서는 Catch 문 뒤에 추가적인 when 조건문을 사용한다.
try{
// ..
}
catch(Exception ex) when(ex.NativeErrorCode == 0x10)
{
//
}
기존 C#에서 딕셔너리를 초기화하는 스타일
과 초기화 후 사용하는 스타일
간에 약간의 차이가 있었다. 딕셔너리를 사용할 때 기존에는 []을 쓰고 선언시에는 []을 쓰지 않았는데 통일했다는 점에서 의의가 있다.
// 처음 초기화 시 ( 이전 )
var scores = new Dictionary<string, int>(){
{"namellllllllllll
}
int sc = scores["lee"]
// C#6 ~
var scores = new Dictionary<string,int>(){
["kim"] = 100,
["lee"] = 90
}
int sc = scores["lee"];
?
, ?.
널 조건 연산자는 ? 앞에 있는 개체가 null인지 체크해서 null 이면 그냥 null을 리턴하고 그렇지 않으면 ? 다음의 속성이나 메서드를 실행한다. 이렇게 하면 일일히 if 문을 써서 null 체크할 필요 없이 축약해서 개발자의 의도를 표현할 수 있다.
인덱서나 배열에서는 ?[]로 표현할 수 잇다.
// rows가 null이면 cnt도 null
// row가 null이 아니면 cnt는 실제 rows 개수
int? cnt = rows?.Count;
// customers 컬렉션이 null이면 c는 null
// 아니면 c는 첫번째 배열요소
Customer c = customers?[0]
// customers가 널인지 체크하고
// 다시 customer[0]이 null인지 체크
int? age = customers?[0]?.Age;
널 조건 연산자만을 사용하게 되면, 리턴 변수는 항상 null을 가질 수 있는 Nullable 타입이어야 한다. (ex : int?, double?)
?.연산자 앞의 값이 null일 경우에 null을 리턴해야하기 때문이다. 만약에 리턴 변수가 null을 가질 수 없는 경우라면? 혹은 null이 아니어야 한다면 ??연산자
를 쓰면 된다. null 일 경우에 ?? 뒤의 디폴트 값을 리턴하는 것이다.
이렇게 하면 받는 타입이 널가능형일 필요가 없다.
널 조건 연산자를 활용하는 대표적인 예는 이벤트를 호출 : Fire
하는 것이다.
기존의 C#에서 이벤트를 Fire하는 루틴은 크게 3가지 단계가 있었다.
아래의 단계는 이벤트 핸들러가 여러 스레드에 의해서 등록되거나 취소될 수 있으므로, 이벤트 호출 시 이벤트 핸들러 목록이 변경되지 않도록 하는 것이다.
여기서 첫번째 이벤트를 로컬 변수에 할당하는 이유는 스레드안전
때문이다.
만약에 이 할당을 하지 않으면, 두번째 단계인 널 체크가 끝나고 세번째 Invoke 단계에 들어가기 직전에 다른 스레드가 이벤트 핸들러를 Unsubscribe
할 경우 이벤트 필드가 Null이 되어 널참조
가 발생할 수 있기 때문이다.
public class MyButton{
public event EventHandler Clicked;
// 이전 방식
public void Click1(){
// -- 1단계 --
var tempClicked = Clicked;
// -- 2단계 --
if( tempClicked != null ){
// -- 3단계 --
tempClicked(this, null);
}
}
// C# 6.0 방식
public void Click2(){
Clicked?.Invoke(this, null);
}
}
해당 글은 https://www.csharpstudy.com/Latest 를 참고하여 작성하였음을 알립니다. 이 글의 목적은 본인의 학습복습입니다.