C# Delegate

델리게이트는 함수 포인터 이다.

왜 사용하는가? - 확장이 쉽게 가능하게 하기위해 사용한다. 예를들면 버튼을 만들면 버튼이 클릭될때
동작하는 것을 정의를 해야한다. 어떻게 해야할가?버튼은 마이크로소프트에서 제공을 한다고하고 나는 내가 만든 로직을 버튼 누르면 실행하게하고 싶다..마소에서 자기들 코드를 고쳐주지 않는다. 그러므로 마소에는 델리게이트를 받게끔 코딩을 해두고 난 델리게이트를 만들어서 그걸 넘겨주면된다. 그러므로 확장성이 잇게 된다. 결론 - 함수를 전달함으로 어플리케이션의 확장성이 추가 된다.

기존 코드

public class Photo
{
    public static Photo Load(string path)
    {
        return new Photo();
    }

    public void Save()
    {
        Console.WriteLine("Save");
    }
}

public class PhotoFilters
{
    public void ApplyBrightness(Photo photo)
    {
        Console.WriteLine("Apply brightness");
    }

    public void ApplyContrast(Photo photo)
    {
        Console.WriteLine("Apply contrast");
    }

    public void Resize(Photo photo)
    {
        Console.WriteLine("Resize photo");
    }
}

public class PhotoProcessor
{
    public void Process(string path)
    {
        var photo = Photo.Load(path);
        
        var filters = new PhotoFilters();
        filters.ApplyBrightness(photo);
        filters.ApplyContrast(photo);
        filters.Resize(photo);

        photo.Save();
    }
}

class Program
{
    static void Main(string[] args)
    {
        var processor = new PhotoProcessor();
        processor.Process("photo.jpg");
    }
    
    static void RemoveRedEyeFilter(Photo photo)
    {
        Console.WriteLine("Apply RemoveRedEye");
    }
}

문제점 - PhotoFilter가 프레임 워크라고 보면 내가 만든 RemoveRedEyeFilter를 프레임워크에 전달하여 사용할 방법이 없다.

해결 가능 방법 PhotoFilter가 내가 만든 함수를 전달 받아서 처리해주면 된다.

해보자. 포토와 포토 필터는 내가 수정하지 않는다.

public class PhotoProcessor
{
    public delegate void PhotoFilterHander(Photo photo);
    // Delegate 선언 
    public void process(string path, PhotoFilterHander filter) // process가 이제 delegate를 파라미터로 받는다. 
    {
        var photo = Photo.Load(path);
        filter(photo); // 파라메터로 받은 함수를 사용한다. 
      
        photo.Save();
    }
}
  1. Delegate 선언 return 타입과 파라미터를 선언한다. - 난 이렇게 생긴 함수면 다 받아들일 준비가 되잇다..이런뜻.

  2. 파라메터로 delegate를 받는다.
  3. 적용한다.

이제 main에서 사용해보자 .

class Program
{
    static void Main(string[] args)
    {
        var processor = new PhotoProcessor(); // processor가 델리게이트 받을 준비가 됬다.
        var filters = new PhotoFilters();

        //델리게이트를 processor에 넣어주자. 
        PhotoProcessor.PhotoFilterHander filterHandler = filters.ApplyBrightness;
        filterHandler += filters.ApplyContrast;  //+=로 함수들을 연결해서 보낼수가 있다. 
        filterHandler += RemoveRedEyeFilter; // 내가 만든 함수도 리턴타입과 파라미터가 같기 때문에 보낼수 있다.

        processor.Process("photo.jpg", filterHandler);
    }

    static void RemoveRedEyeFilter(Photo photo)
    {
        Console.WriteLine("Apply RemoveRedEye");
    }
}

이렇게 해주면 내가 만든 함수도 리턴타입과 파라미터가 void , Photo photo 로 같기 때문에 기존 processor에 보낼수 있다. processor가 프레임워크 수준이라면 이런식으로 확장성을 늘릴수가 있다.

Func , Action

.net 프레임워크에서 델리게이트를 미리 만들어서 뒀다 우리는 이걸 사용할수 있다.

Func와 Action이다. 이름은 이렇지만 델리게이트이다.

Func는 return 이 있고

Func < int, int int>  // 마지막 int를 return 

Action은 return 이 없다.

Action <int,int,int>  // 마지막 Int는 파라미터 

둘다 0개부터 16개의 파라미터를 받을수 있게 되잇다.

Generic으로 파라미터를 받기 때문에 대부분의 델리게이트를 만드는경우 이걸 쓰면된다. 16개가 넘어가는경우에만 만들 의미가 있겟지.

Func<in T,out T2>   //T2가 리턴값
Action<in T,in T2> 

이제 코드를 이걸로 바꿔보자.

public class PhotoProcessor
{
    public void Process(string path, Action<Photo> filterHandler)
    {
        var photo = Photo.Load(path);

        filterHandler(photo); //받은 함수를 적용한다. 

        photo.Save();
    }
}

delegate를 지웟고 Process 파라미터에서 Action 타입을 받는다.

class Program
{
    static void Main(string[] args)
    {
        var processor = new PhotoProcessor();
        var filters = new PhotoFilters();
        Action<Photo> filterHandler = filters.ApplyBrightness; //delegate를 사용하지 않고 Action을 사용함.
        filterHandler += filters.ApplyContrast;
        filterHandler += RemoveRedEyeFilter;

        processor.Process("photo.jpg", filterHandler);
    }

    static void RemoveRedEyeFilter(Photo photo)
    {
        Console.WriteLine("Apply RemoveRedEye");
        
    }
}

Action을 사용함 그러므로 리턴타입은 없고 action< 다음에 photo 하나만 잇으므로 파라미터가 1개 photo인 함수를 대표한다고 볼수가 잇다.

나머지는 똑같다.

실행해보면 결과가 같다는 것을 알수 있다.

이렇게 델리게이트를 사용하면 프레임워크의 확장성을 미리 준비해둘수가 있다.

teamsmiley's profile image

teamsmiley

2016-12-26 00:00

Read more posts by this author