강께르의 개발일지
[수업] 20210917_5일차 본문
열거형
열거형에서 비트 플래그를 사용하는 방법
[Flags] <- attribute 데이터 선언이나 멤버 선언 위에 붙여 그 데이터형에 속성을 부여한다.
enum 식별자
1, 2, 4, 8 = 1 << 0, 1 << 1, 1 << 2, 1 << 3
BorderSides leftRight = BorderSides.Left | BorderSide.Right
if(leftRight & BorderSides.Left) != 0) // 비트마스크 체크
leftRight.ToString(); Left, Right
특정 비트로 토글하고 싶으면 XOR 연산을 하면 된다. 같으면 false 다르면 true
Enum.IsDefined(typeof(enum클래스), 변수))
유효한 enum값인지 체크하는 메소드 / 플래그가 아닌 경우에만 체크할 수 있다.
플래그에서는 enum 값이 섞여 있기 때문에 명시적인 enum값을 가지지 않을 수 있기 때문이다.
플래그 케이스일 때 검사
정수형 데이터형이 가지고 있는 TryParse()가 있다.
TryParse(enum 값의 ToString(), out 정수형 변수)를 넣으면 enum값을 정수형 데이터로 형 변환을 시도할 것이고
형 변환의 결과로 성공하면 반환값 true를, 실패하면 반환값 false가 나올 것이다.
그리고 성공하면 정수형 변수에 enum값의 ToString()의 정수로 변환된 값이 대입될 것이다.
실패하면 0을 대입한다.
정수와의 산술 연산이 가능하다.
내부 타입
클래스 내부에
다른 클래스를 구현 : nested class
enum을 구현 : nested enum
nested의 특징
private nested 클래스가 private static 멤버를 참조할 수 있다.
public으로 설정해야 바깥에서 사용 가능하다.
제네릭(Generics, 일반화 프로그래밍)
템플릿과 유사하다.
일반화 인자 / 제네릭 인자 : 제네릭에서 쓰는 매개 변수 (데이터형 이름 T)
제네릭 클래스를 사용하는 방법
< > 안에 데이터형을 대입하여 선언
템플릿 : 런타임이 아닌 컴파일 타임에 만들어져서 실제와 연결
-> 필요하네? 만들어놔야겠다.
제네릭 : 런타임에 만들어져서 연결
-> 필요하네? 이제 만들어서 써야지.
제네릭 클래스를 만드는 방법
기존의 클래스를 데이터형으로 특정화하고 싶다.
모든 멤버를 일반화하지 않고 원하는 특정 부분만 골라서 구현해야한다.
Boxing / unboxing이 일어나지 않는 좋은 방법이다.
오브젝트, 인터페이스의 업캐스팅으로 하는 것을 지양하고 제네릭 프로그래밍을 사용해라.
인터페이스는 비일반화 / 일반화 버전이 있기에 일반화 버전으로 사용해서 object형으로 매개변수를 받는 함수를 오버라이딩할 필요 없게 해라.
제네릭 메소드
메소드 이름 옆에 <데이터형>을 넣어라.
실제 사용할 때는 생략 가능하다. 매개변수를 보고 미루어 짐작
클래스와 별개로 일반화 인자를 가질 수 있다. 메소드만 가능한 기능이다.
제네릭으로 선언한 프로퍼티
데이터형으로 제네릭 인자 사용가능
default(T);
디폴트값을 이용해 초기화를 할 수 있다
디테일한 부분
데이터형에 제약을 걸 수 있다.
예 ) 참조형만, 값형만, 이 클래스를 상속받은 자식 클래스만 등등
클래스 이름<T> where T : 제약 사항
제약사항을 하나 이상 걸수 있다.
제네릭 인자마다 걸수도 있다.
제약사항은 컴파일 타임에 다 체크한다.
델리게이트
C#의 기본으로 제공되는 클래스에는 델리게이트를 쓰는 것이 많다.
델리게이트를 이용해 메소드를 전달하기 때문이다.
System.delegate에 있는 내용이다.
델리게이트의 의미
데이터형을 의미 -> 이를 통해 변수를 생성(이 변수도 델리게이트라고 부른다.)
메소드를 참조하는 데이터형
ex)
delegate int Transformer (int x);
Transformer t = Square;
델리게이트 변수에 메소드를 담는 것.
+ 참조하고 있는 변수로 메소드를 호출
+ 델리게이트가 메소드를 1대1 참조가 아닌 n개를 참조한다.
데이터형이 되면 좋은 점
다른 클래스의 멤버가 되거나 다른 클래스의 메소드의 매개변수가 될 수 있다.
delegate (반환형) (델리게이트 이름);
반환형과 매개변수가 같은 메소드만 델리게이트로 할당 가능
델리게이트 인스턴스를 만들어서 참조
호출하는 방법
변수이름(매개변수) -> 일반적인 함수 호출방법과 유사
invoke : 참조하고 있는 함수를 호출하는 델리게이트 메소드
스태틱과 인스턴스 메소드 상관없이 클래스의 메소드를 받아올 수 있다.
인스턴스 메소드를 저장하는 것은 인스턴스의 멤버를 이용해서 할 수 있기에 그 델리게이트에는 인스턴스의 정보도 들어가 있다.
p.Target == r
Target 인스턴스 비교 검사 메소드
Method 현재 참조하고 있는 메소드 이름을 string으로 반환한다.
델리게이트는 참조하고 있는 참조형 변수여서 인스턴스의 내용이 바뀌면 델리게이트도 다른 결과를 반환한다.
n개의 메소드를 참조하는 방법
기존의 참조하는 메소드를 유지하고 새 메소드를 추가하고 싶으면
+= 연산자로 메소드를 피연산자로 사용한다.
-= 연산자로 메소드를 피연산자로 제거한다.
null을 할당한다는 것은 참조하고 있는 메소드가 없는 것을 의미한다.
멀티캐스트
사용하는 것은 위의 델리게이트 호출 방법이랑 똑같은데
동작하는 모습이 다르다.
할당된 순서대로 메소드가 호출한다.
그리고 중간에 반환값이 있어도 버리고, 제일 마지막에 추가된 메소드의 반환값을 반환한다.
제네릭 델리게이트
제네릭 메소드의 메소드로 제네릭 델리게이트를 매개변수를 필요로 할 수 있다.
그래서 해당 제네릭 메소드를 호출할 때, 반환형과 데이터형을 신경써서 델리게이트를 할당한다면
제네릭하여 다양하게 쓸 수 있다.
미리 정의된 델리게이트가 System에 있다.
Func<TResult> / Action<T>
내가 정의하지 않고 System의 것을 갖고와 사용할 수 있다.
Func : 반환형이 있는 것 / 마지막 참조 메소드의 반환형이 Func의 반환형
Action : 반환형이 없는 것 / ref로 매개변수 넘기는 것들은 Action으로 하면 안된다.
사용자 정의를 안쓰고 Func, Action을 써도 되는데
사용자 정의 이름이 필요한 경우에는 만들어서 써도 된다.
인터페이스를 상속받은 클래스를 함수용도로 델리게이트 대신 사용할 수도 있다.
그런데 델리게이트가 더 효율적이다. 함수만 쓸거면... 멀티캐스트도 안되고...
델리게이트들은 데이터형이 다르면 가르키는 함수가 같아도 할당이 안된다.
D1 d1 = Method1;
D2 d2 = d1; // X
델리게이트끼리의 비교연산은 가르키고 있는 타겟이 같은지 비교한다.
상속구조에 의해서 델리게이트를 object형에 할당해서 굴릴 수 있으나 굳이..?
Func<string> x = Function;
Func<object> y = x; // allow
이 경우 내가 이해하기론 반환형이 string인 함수를 가진 델리게이트 변수를
반환형이 object인 델리게이트 변수에 대입해도 업캐스팅하는 문제이기에 상관 없는 것 같다.
'프로그래밍 > C#' 카테고리의 다른 글
[수업] 20210923_6일차 (0) | 2021.09.24 |
---|---|
[문제 풀기] Bit Flags, Generics, Delegate에 대하여 (0) | 2021.09.18 |
[문제 풀기] boxing, unboxing과 인터페이스에 대하여 (0) | 2021.09.17 |
[수업] 20210916_4일차 (0) | 2021.09.17 |
[문제 풀기] 클래스에 관하여 (0) | 2021.09.16 |