# 델리게이트(Delegate)

 해석하면 '대리인'이라는 뜻의 델리게이트는 C++의 포인터처럼 메서드를 안전하게 캡슐화하는 형식입니다.
즉, 메소드를 대신해서 호출하는 역활을 하는 메소드를 참조하는 변수입니다.
특정 메소드를 처리할 때 그 메소드를 직접 호출해서 실행시켜야 했지만, 델리게이트를 사용하면 그 메소드를 대신하여 호출할 수 있습니다.

# 사용방법
(1) 델리게이트 타입 선언.
    메소드 타입은 매개변수와 반환타입에 의해 결정됩니다.
    델리게이트 타입도 그 메소드와 동일한 매개변수, 반환 타입으로 선언해주면 됩니다. 
(2) 델리게이트 인스턴스화하여 메서드 전달.

(3) 델리게이트 호출.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
namespace DelegateTest
{
    class Program
    {
        delegate void Del(string message);
        public static void DelegateMethod(string message)
        {
            System.Console.WriteLine(message);
        }
        static void Main(string[] args)
        {
            // 명명된 메서드 전달.
            Del handler = DelegateMethod;
            // 무명 메서드 전달.
            Del handler2 = delegate (string message)
                            { System.Console.WriteLine(message); };
            // 람다식 활용.
            Del handler3 = (message) => System.Console.WriteLine(message);
            handler("Hello World");
            handler2("Bye World");
        }
    }
}
cs

# 콜백 메서드
인스턴스화 된 델리게이트는 매개 변수로 전달하거나 속성에 할당할 수 있습니다.
따라서, 메서드가 델리게이트를 매개 변수로 허용하여 매개 변수로 받은 델리게이트를 나중에 호출할 수 있습니다. 

이러한 방식을 비동기 콜백이라고 부르며, 콜백 메서드를 구현할 때, 델리게이트의 가치를 볼 수 있습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
namespace Calculater
{
    delegate int Calc(int a, int b);
 
    class MainApp
    {
        public static void Calculator(int a, int b, Calc cb)
        {
            Console.WriteLine(cb(a, b));
        }
 
        public static int Plus(int a, int b) { return a + b; }
        public static int Minus(int a, int b) { return a - b; }
 
        static void Main(string[] args)
        {
            Calc plusCalc = new Calc(Plus);
            Calc MinusCalc = new Calc(Minus);
 
            Calculator(1122, plusCalc);  // 33 출력
            Calculator(3322, MinusCalc); // 11 출력
        }
    }
}
cs



# 델리게이트 체인

델리게이트는 둘 이상의 메서드를 호출할 수 있습니다. 이러한 호출을 멀티캐스트라고 합니다.

델리게이트에 메서드 목록을 추가하려는 경우, 더하기 또는 더하기 대입 연산자('+' 또는 '+=')를 사용합니다. 

메서드 제거도 가능한데, 제거하는 경우엔 감소 또는 감소 대입 연산자('-' 또는 '-=')를 사용하면 됩니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
namespace Multicast
{
    delegate void PrintText();
 
    class MainApp
    {
        public static void First() { Console.Write("첫번째 "); }
        public static void Second() { Console.Write("두번째 "); }
        public static void Third() { Console.Write("세번째 "); }
 
        static void Main(string[] args)
        {
            PrintText MultiHandler;
 
            MultiHandler = new PrintText(First);
            MultiHandler += Second;
            MultiHandler += Third;
 
            Console.WriteLine("메서드 추가");
            MultiHandler();
 
            MultiHandler -= First;
            MultiHandler -= Third;
 
            Console.WriteLine("\n\n메서드 제거");
            MultiHandler();
        }
    }
}
cs



    [ 콘솔 출력 결과 ]


    메서드 추가

    첫번째 두번째 세번째


    메서드 제거

    두번째





delegate 관련 Effective C# : https://loveme-do.tistory.com/14


참   고 : https://mrw0119.tistory.com/19?category=585887

           https://docs.microsoft.com/ko-kr/dotnet/csharp/programming-guide/delegates/using-delegates

nullable 형식 한정자




nullable 형식은 기본 값 형식의 모든 값과 추가로 NULL 값을 나타내는 형식입니다. 


Nullable<T> 또는 T? 의 형태로 사용할 수 있으며, struct와 임의의 값 형식이 될 수 있지만 참조 형식은 될 수 없습니다.


1
2
3
4
5
6
7
int a = null;
// 컴파일 에러
// int는 null을 허용하지 않는 형식.
 
int? b = null;
 
int result = b ?? 0;
cs


??(null 병합 연산자)나 ?.(null 조건부 연사자)와 같이 C#에서 null 값을 체크해주는 연산자들이 있습니다. 


이런 연산자를 사용하다 보면 null 값을 허용하지 않는 형식에도 사용이 필요한 경우가 있습니다.


이 때, nullable 형식 한정자를 사용하게 되면 null 값과 함께 내부 형식 값도 모두 나타낼 수 있습니다.



. null 병합 연산자 : https://loveme-do.tistory.com/8

. null 조건부 연산자 : https://loveme-do.tistory.com/7






참   고 : https://docs.microsoft.com/ko-kr/dotnet/csharp/programming-guide/nullable-types/using-nullable-types

?? 연산자 (null 병합 연산자)



 
?? 연산자는 피연산자가


1. NULL일 경우, 오른쪽 피연산자를 반환.

2. NULL이 아닐 경우, 왼쪽 피연산자를 반환.


1
2
3
int? a = null;
 
int cnt = a ?? 10;
cs


위와 같을 때,

anull 이라면, cnt = 10;

anull 이 아니라면, cnt = a; 의 값이 대입되게 됩니다. 


객체가 null인 경우에 대한 디폴트 값을 설정해 주거나, 이러한 상황을 안전하게 처리할 수 있습니다. 





참  고 : https://docs.microsoft.com/ko-kr/dotnet/csharp/language-reference/operators/null-coalescing-operator

?. 연산자 (null 조건부 연산자)



 null 조건 연산자는 ? 앞에 있는 객체가 NULL인지 체크해서


1. NULL 이라면, NULL을 리턴.

2. NULL이 아니라면, ? 다음의 속성이나 메서드를 실행.


일반적으로 ?. 와 같이 표현되지만, 만약 인덱서 혹은 배열 요소에 적근할 경우는 ?[]와 같이 표현된다.


1
2
3
4
5
6
7
8
9

// customer 컬렉션이 null 이면 cnt는 null
// null이 아니라면, cnt는 customer의 갯수.
int? cnt = customer?.Count;
 
// customer가 null인지 체크하고
// 다시 customer[0]가 null인지 체크한다.
// customer이 null이거나 customer[0]이 null이라면 age는 null
// 그렇지 않다면, age는 customer[0].age
int? age = customer?[0]?.age;

cs



null 조건부 연산자를 사용하면 null 참조될 수 있는 객체에 안전하게 접근할 수 있으며,

null에 대한 예외 처리를 축약해서 개발자의 의도를 표현할 수 있다.






참  고: http://www.csharpstudy.com/CS6/CSharp-null-conditional-operator.aspx


C# 사용자 정의 형변환 - explicit, implicit



 두 기능 모두 C#4.0부터 지원해주고 있는 기능입니다.

explicit
 명시적 사용자 정의 형변화 연산자.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
class Celsius
{
    private float degress;
 
public Celsius(float degress)
    {
        this.degress = degress;
    }
    //Celsius -> Fahrenheit 명시적 형변환.
    public static explicit operator Fahrenheit(Celsius c)
    {
        return new Fahrenheit((9.0f / 5.0f) * c.degress + 32);
    }
    public float Degress
    {
        get { return this.degress; }
    }
}
 
class Fahrenheit
{
    private float degress;
 
    public Fahrenheit(float degress)
    {
        this.degress = degress;
    }
    //Fahrenheit -> Celsius 명시적 형변환.
    public static explicit operator Celsius(Fahrenheit fahr)
    {
        return new Celsius((5.0f / 9.0f) * (fahr.degress - 32));
    }
    public float Degress
    {
        get { return degress; }
    }
}
 
class TextExplicit
{
    static void Main()
    {
        Fahrenheit fahr = new Fahrenheit(100.0f);
        Celsius c = (Celsius)fahr; // Fahrenheit -> Celsius explicit conversion.
 
        Fahrenheit fahr2 = (Fahrenheit)c; //Celsius -> Fahrenheit explicit conversion.
    }
}



- implicit
 암시적 사용자 정의 형변화 연산자.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Digit
{
    byte value;
 
    public Digit(byte value)
    {
        if (value > 9)
        {
            throw new System.ArgumentException();
        }
        this.value = value;
    }
    // byte -> Digit 암시적 형변환.
    public static implicit operator Digit(byte b)
    { 
        return new Digit(b);
    }
    // Digit -> byte 암시적 형변환.
    public static implicit operator byte(Digit d)
    {
        return d.value;
    }
}
 
class TextImplicit
{
    static void Main()
    {
        Digit d = new Digit(3);
        byte b = d; // Digit -> byte implicit conversion.
 
        Digit dig2 = b; // byte -> Digit implicit conversion.
    }
}






참 고 : https://docs.microsoft.com/ko-kr/dotnet/csharp/programming-guide/statements-expressions-operators/using-conversion-operators

C# 선택적 매개 변수와 명명된 매개 변수.



 두 기능 모두 C#4.0부터 지원해주고 있는 기능입니다.

-
선택적 매개변수
 C++
에서의 디폴트 매개 변수와 같은 기능으로, 매개 변수를 필수 또는 선택 사항으로 지정할 수 있습니다.
호출 시 모든 필수 매개 변수에 대한 인수를 제공해야 하지만 선택적 매개 변수에 대한 인수는 생략할 수 있습니다.
이 때, 선택적 매개 변수에 대해서는 기본값을 필수적으로 제공해주고 있어야하며, 필수 매개 변수 다음으로 정의해야 합니다.

 선택적 매개 변수 지원 이전에는 다음과 같이 필요한 매개 변수에 따른 함수 오버로딩으로 정의해야 했는데.....


void Person(string name);

void Person(string name, int age);
void Person(string name, int age, string address);


 위의 코드를 선택적 매개 변수 기능으로 아래와 같이 수정 가능해졌습니다!

 

void Person(string name, int age = 0, string address = “None”);



-
명명된 매개 변수
호출된 메서드, 각 인수에 대한 매개 변수를 매개 변수 이름으로 지정할 수 있습니다.


 

Person(name: “승엽, address: 서울특별시, age: 25);


 위와 같이 각 인수에 대한 매개 변수를 매개 변수 이름으로 지정하여 사용할 수 있습니다.
각 인수가
 무엇을 나타내는지 식별할 수 있어 코드의 가독성을 향상시킬 수 있고, 임의의 순서로 인수를 보낼 수 있습니다.

 또한, 위의 Person의 선택적 매개 변수 중 address에만 인자를 보내고 싶을 경우에 다음과 같은 처리도 가능합니다.

 

Person(“민호, address: 경기도);








참 고 : https://docs.microsoft.com/ko-kr/dotnet/csharp/programming-guide/classes-and-structs/named-and-optional-arguments

+ Recent posts