늘 기억한다고 하면서도 어떤 것들은 코딩할때 예전방식대로 코딩 하고 있는 내 자신을 본다.
다시한번 상기시키기위해 정리해본다.
참고 : 정성태님 자료.
1. out 매개변수
이전에는 out 매개변수를 미리 선언했어야 하나 7.0 부터는 변수 선언없이 out 예약어를 쓸수 있다.
C# 7 컴파일러는 위의 구문을 컴파일하는 경우 개발자 대신 C# 6 이전의 코드로 변환해 소스코드를 컴파일한다.
var 예약어도 사용할 수 있다.
심지어 값을 무시하는 구문까지 추가되어 값이 필요하지 않은 상황에 대해서는 변수명까지 생략할 수 있다. (이건 굳이 필요가?.;)
int.TryParse("5", out var _ );
2. ref 예약어
이전에는 메서드의 매개변수로만 사용가능했지만 로컬변수와 번환값에서도 사용할 수 있다.
ref int b = ref a;
위처럼 하고 사용하게되면 a, b 변수는 동일한 메모리를 공유하게 된다.
반환값으로 사용하는 경우는 이전에는 메서드에서 배열의 특정 요소를 변경한 결과를 넘겨주기위해 귀찮게 작업하던걸 아래처럼 처리할수 있다.
ref int item = ref intList.GetFirstItem();
item = 5; // 참조값이므로 값을 변경하면 원래의 int [] 배열에도 반영
intList.Print(); // 출력 결과: 5,2,
class IntList
{
int[] list = new int[2] { 1, 2 };
public ref int GetFirstItem()
{
return ref list[0];
}
internal void Print() { ……[생략]…… }
}
3. 튜플
튜플(Tuple)이란 유한 개의 원소로 이뤄진 졍렬된 리스트를 의미하는 자료구조다.
어떤 메서드의 결과가 두가지를 도출할때 이전에는 아래처럼 class 를 정의해서 사용했지만 튜플을 이용하면 사용하기 쉽다.
{
public int ResultInt {get; set;}
public bool ResultBool {get; set;}
}
public Result TestMethod()
{
Result result = new Result(){ ResultInt =0, ResultBool = false};
return result;
}
dynamic 를 이용해서 아래처럼 어느정도 해결은 가능하다.
{
return new { ResultInt =0, ResultBool = false };;
}
하지만 dynamic의 도입으로 정적 형식 검사를 할 수 없어 나중에 필드 이름이 바뀌어도 컴파일 시 문
제를 알아낼 수 없다는 문제점이 발생한다.
닷넷 프레임워크 4.0의 BCL부터 제공되는 System.Tuple 제네릭 타입을 이용하면 7개까지의 인자를 기본 처리할 수 있도록 미리 정의돼 있으며,
public class Tuple<T1> : IStructuralEquatable, …[생략]…, ITuple
public class Tuple<T1, T2> : IStructuralEquatable, …[생략]…, ITuple
public class Tuple<T1, T2, T3> : IStructuralEquatable, …[생략]…, ITuple
public class Tuple<T1, T2, T3, T4> : IStructuralEquatable, …[생략]…, ITuple
public class Tuple<T1, T2, T3, T4, T5> : IStructuralEquatable, …[생략]…, ITuple
public class Tuple<T1, T2, T3, T4, T5, T6> : IStructuralEquatable, …[생략]…, ITuple
public class Tuple<T1, T2, T3, T4, T5, T6, T7> : IStructuralEquatable, …[생략]…, ITuple
8개 이상은 또 다른 System.Tuple로 이어서 처리할 수 있도록 구현돼 있다.
public class Tuple<T1, T2, T3, T4, T5, T6, T7, TRest> : IStructuralEquatable, …[생략]…, ITuple
따라서 위 문제는 아래처럼 해결이 가능하다.
{
int number = 0;
bool result = false;
return Tuple.Create(number, result );
}
Tuple<int, bool> result = TestMethod();
Console.WriteLine(result.Item1);
Console.WriteLine(result.Item2);
또한 C# 7.1부터 튜플에 대해 타입 추론이 추가되어 이름 지정을 생략할 수 있는 경우가 있다
여기서 부터는 코드가 무슨 암호가 되버린 느낌이다;;
{
int number = 0;
bool result = false;
return (number, result);
}
(int, bool) result = TestMethod();
Console.WriteLine(result.Item1);
Console.WriteLine(result.Item2);
변수의 이름이 무조건 Item1,Item2, ……와 같은 식으로 정해진다는 아쉬움이 남는다.
하지만 이런 모든 문제를 해결하기 위해 마이크로소프트는 C# 언어 차원에서 튜플을 지원하기로 결정했고 이로 인해 메서드의 정의 구문이 확장된다.
그래서 이제 아래 처럼 사용하여 이름을 지정할수 있다. (var 도 가능)
{
int number = 0;
bool result = false;
return (number, result);
}
(int , bool) result = TestMethod();
Console.WriteLine(result.ResultInt );
Console.WriteLine(result.ResultBool);
메서드에서 정의 하지 않고 받는 곳에서 정의도 할수 있다.
{
int number = 0;
bool result = false;
return (number, result);
}
(int ResultInt , bool ResultBool) result = TestMethod();
Console.WriteLine(result.ResultInt );
Console.WriteLine(result.ResultBool);
5. 람다 식을 이용한 메서드 정의 확대
C# 6.0의 람다 식으로 메서드의 정의가 가능했던 유형은 다음과 같다.
■ 일반 메서드
■ 속성의 get 접근자(읽기 전용으로 처리됨)
■ 인덱서의 get 접근자(읽기 전용으로 처리됨)
C# 7.0부터는 람다 식의 접근이 다음의 메서드 정의까지 확장됐다.
■ 생성자(Constructor)
■ 소멸자(Destructor)
■ 이벤트의 add/remove
■ 속성의 set 구문
■ 인덱서의 set 구문
아래 예시를 보면 깔끔하게 정리된다.
{
double x;
double y;
public Vector(double x) => this.x = x; // 생성자 정의 가능
public Vector(double x, double y) // 생성자이지만 2개의 문장이므로 람다 식으로 정의 불가
{
this.x = x;
this.y = y;
}
~Vector() => Console.WriteLine("~dtor()"); // 소멸자 정의 가능
public double X
{
get => x;
set => x = value; // 속성의 set 접근자 정의 가능
}
public double Y
{
get => y;
set => y = value; // 속성의 set 접근자 정의 가능
}
public double this[int index]
{
get => (index == 0) ? x : y;
set => _ = (index == 0) ? x = value : y = value; // 인덱서의 set 접근자 정의 가능
}
private EventHandler positionChanged;
public event EventHandler PositionChanged // 이벤트의 add/remove 접근자 정의 가능
{
add => this.positionChanged += value;
remove => this.positionChanged -= value;
}
public Vector Move(double dx, double dy)
{
x += dx;
y += dy;
positionChanged?.Invoke(this, EventArgs.Empty);
return this;
}
public void PrintIt() => Console.WriteLine(this);
public override string ToString() => string.Format("x = {0}, y = {1}", x, y);
}
6. 지역함수
아래 코딩만 참고하자
{
(bool, int) func(int a, int b) => (b == 0) ? (false, 0) : (true, a / b);
Console.WriteLine(func(10, 5));
}
7 자유로워진 throw 사용
이전에는 아래처럼 Throw 를 표현식에서 사용이 불가하여 처리하기위해 별도 메서드를 만들어서 호출했으나
public bool AssertException(string msg) => throw new ApplicationException(msg);
이제는 그러지 않아도 된다.
public bool Assert(bool result) => result == true ? result : throw new ApplicationException("ERROR!!");
다음 코드에서 볼 수 있는 것처럼 null 병합 연산자(??)와 람다식을 사용할 수 있는 곳 에서 throw를 사용할 수 있다.
{
public string Name { get; }
// null 병합 연산자(??)에서 throw 사용 가능
public Person(string name) => Name = name ?? throw new ArgumentNullException(nameof(name));
// 람다 식으로 정의된 메서드에서 사용 가능
public string GetLastName() => throw new NotImplementedException();
public void Print()
{
// 단일 람다 식을 이용한 델리게이트 정의에서 사용 가능
Action action = () => throw new Exception();
action();
}
}
* 표현식이 허용되는 모든 곳에서 사용가능한건 아니다.
continue...
'C# > Winform' 카테고리의 다른 글
system.windows.interactivity 관련 에러 -Visual Studio 2017 (0) | 2018.01.06 |
---|---|
C# 7.0 기억해야 할 변경점 - 2 (0) | 2018.01.02 |
(C#) 특수문자 제거 정규식 (0) | 2017.12.27 |
(C#) Double/float 연산 결과가 이상할 때 (부동소수점 연산) (0) | 2017.12.22 |
Azure 무료계정 신청하기 (0) | 2017.11.27 |