2014년 11월 4일 화요일

31. C# Delegate(델리게이트), C#델리게이트체인,delegate chain, 버블정렬,Bubble Sort[닷넷C#교육/ADO.NET강좌/ASP.NET교육잘하는곳/C#,ASP.NET교육추천/닷넷실무교육/.NET,C#/ADO.NET교육/닷넷학원/ASP.NET실무교육]

C# Delegate(델리게이트), C#델리게이트체인,delegate chain, 버블정렬,Bubble Sort
 
델리게이트(Deligate)는 대리자라고 하는데 C의 함수 포인터와 유사한데 메소드의 참조를 포함한다자기 자신이 실제로 하는 일은 없고 단지 자기가 가리키고 있는 메서드(함수)를 호출하는 역할을 하는 것이다.
:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /> 
결국 델리게이트(Delegate)는 메소드에 대한 참조를 저장 하는 것인데 이렇게 메소드에 대한 참조를 가리키고 있다는 것으로 인해 불가능한 작업등이 가능해진다예를 들면 Delegete를 다른 함수의 인자로 넘겨주게 되면 그 함수는 델리게이트가 보내 주는 함수의 참조를 이용하여 실행 시점에 호출될 함수를 결정 할 수 있는 것이다.
 
델리게이트의 이해를 위해서는 콜백(CallBack)에 대해 알아야 하는데 어떤 일을 해줄 코드를 두고 실제 할 일은 컴파일 타임이 아닌 런타임에 부여하는 데 이 을 콜백 이라 한다. C# 델리게이트는 이 콜백을 구현하기 위해 사용되는 것인 데 델리게이트에 메소드의 주소를 할당한 후 델리게이트를 호출하면 델리게이트가 메소드를 호출해 주는 것이다.
 
델리게이트는 쓰레드와 이벤트에서 주로 이용 할 수 있다는 것은 참고로 알아 두자.
 
선언방법
 
한정자 delegate 리턴형 델리게이트이름 ( 매개변수목록 );
 
델리게이트는 메소드에 대한 참조이므로 참조할 메소드의 반환형식과 매개변수를 정의해 주어야 한다구현부가 없는 이유는 delegate 자신은 아무것도 하지 않고자신이 참조하고 있는 메서드(함수)만 호출해 주기 때문 이다.
 
 
델리게이트를 이용하여 콜백을 구현하는 과정
 
1.     델리게이트 선언
2.     델리게이트의 인스턴스 생성(델리게이트가 참조 할 메소드를 매개변수로 넘긴다)
3.     델리게이트를 호출
 
 
아래의 코드를 보도록 하자…
 
int i = int.Parse(5919);
 
일반적으로 대부분의 메서드들이 인자 값을 받아 어떤 일 처리를 하게 된다위의 코드에서 Parse()메서드는 string형의 인자를 받아 int형으로 바꾸어 주는 역할을 하는데대부분의 메서드들이 인자를 받는 이유는 왜일까?
 
메서드들이 인자를 받는 이유는 처리해야 할 값을 runtime시에만 알 수 있기 때문이다예를 들어 숫자를 정렬하는 메서드를 만들었다고 가정하자  사용자가 숫자 몇에서 몇까지를 정렬하기를 원하는지 알 수가 없다따라서나중에 그 값을 입력 받도록 처리 하기 위해 인자를 쓰게 되는 것이다.
Delegate도 이와 같은 개념으로 생각하시면 되며 단지 다른 점이 있다면, value형인 매개변수 대신에 메서드를 인자로 받는다는 것이다.
 
아래의 예제를 보자
 
using System;
public class Delegate1
{
             private delegate string OnjString();
 
             public static void Main(string[] args)
             {
                           int x = 4790;
                           OnjString myMethod = new OnjString(x.ToString);
                           Console.WriteLine("문자열 : {0}", myMethod());
             }
}
 
 
Delegate를 사용할 때 주의할 점은 delegate가 참조하는 메서드(여기서는 ToString) 의 인자 및 리턴형이 선언된 delegate와 같아야 한다는 것이다예제 1에서도 볼 수 있듯이, ToString() 메서드는 인자가 없고, string형을 리턴 한다따라서 선언된 delegate도 인자가 없이 string형을 리턴 하도록 선언되어 있지만 delegate는 참조하는 메서드가 어떤 타입이든 상관 하지 않는다. static이든 non static이든 관계없다참조하는 메서드의 인자형개수리턴 타입만 같으면 문제가 없다는 것 이다.
 
 
[예제2]
 
using System;
 
class OnjMath
{
    internal static double MultipleByTwo(double value)
    {
        return value * 2;
    }
 
    internal static double Square(double value)
    {
        return value * value;
    }
}
 
delegate double OnjDouble(double x);
 
class DelegateTest2
{
    static void Main(string[] args)
    {
        //Delegate 배열로 지정
        OnjDouble[] op =
                                                     {
                                                                       new OnjDouble(OnjMath.MultipleByTwo),
                                                                       new OnjDouble(OnjMath.Square)
                                                     };
 
        for (int i = 0; i < op.Length; i++)
        {
            Console.WriteLine("op[{0}] 호출:", i);
            CallDelegate(op[i], 3.0);  //Delegate 다른 메소드의 인자로 넘긴다.
            //Console.WriteLine("결과는 {0} 이다", op[i](3.0));
            Console.WriteLine();
        }
    }
 
    static void CallDelegate(OnjDouble func, double value)
    {
        //넘겨받은 Delegate 실행 한다.
        double ret = func(value);
        Console.WriteLine("입력된 값은 {0}이고 결과는 {1} 이다", value, ret);
    }
}
 
 
 
위의 예제에서 OnjDelegate라는 메서드를 호출할 필요 없이 곧바로 delegate가 참조하는 메서드를 실행 하려면 다음과 같이하면 된다.
 
op[i](2.0);
 
 
[예제]
using System;
using System.Collections.Generic;
using System.Text;
 
namespace deledatetest
{
    delegate int Onjdelegate(int a, int b);
 
    class MainApp
    {
        static int Plus(int a, int b)
        {
            return a + b;
        }
 
        int Minus(int a, int b)
        {
            return a - b;
        }
 
        static void Main()
        {
            MainApp m = new MainApp();
            Onjdelegate CallBack = new Onjdelegate(MainApp.Plus);
            Console.WriteLine(CallBack(4,4));
 
            CallBack = new Onjdelegate(m.Minus);
            Console.WriteLine(CallBack(4, 4));         
 
        }
    }
}
 
[결과]
8
0
 
이번에는 델리게이트 체인 예제이다.
 
[예제]
 
using System;
using System.Collections.Generic;
using System.Text;
 
namespace deledatetest
{
    delegate void OnjDelegate(int a, int b);
 
    class MainApp
    {
        static void Plus(int a, int b)
        {
            Console.WriteLine("{0} + {1} = {2}", a, b, a+b);
        }
 
        static void Minus(int a, int b)
        {
            Console.WriteLine("{0} - {1} = {2}", a, b, a - b);
        }
 
        void Multiplication(int a, int b)
        {
            Console.WriteLine("{0} * {1} = {2}", a, b, a * b);
        }
 
        void Division(int a, int b)
        {
            Console.WriteLine("{0} / {1} = {2}", a, b, a / b);
        }
 
 
 
        static void Main()
        {
            MainApp m = new MainApp();
            OnjDelegate CallBack = (OnjDelegate)Delegate.Combine(new OnjDelegate(MainApp.Plus),
                                                           new OnjDelegate(MainApp.Minus),
                                                           new OnjDelegate(m.Multiplication),
                                                           new OnjDelegate(m.Division));
            CallBack(4, 3);   
 
        }
    }
}
 
 
[결과]
 
4 + 3 = 7
4 - 3 = 1
4 * 3 = 12
4 / 3 = 1
 
 
델리데이트는 언제 꼭 필요할까?
 
아래와 같은 버블정렬이 있다고 하자.
 
for (int i=0; i<sortArray.Length; i++)
{
     for (int j=0; j<i; j++)
     {
        if (j > i) // 문제의 소지가 있는 부분현재는 오름차순
          {
               int temp = sortArray[i]; // i  j 바꾸기
               sortArray[i] = sortArray[j];
               sortArray[j] = temp;
          }
     }
}
 
만약 이 버블정렬의 데이터가 위와 같은 숫자가 아니라 객체라면 어떻게 될까현재와 같은 구조에선 곤란하다이는 사용자가 어떤 식으로 클래스나 구조체 등을 정의해 놓았는지 알 수가 없기 때문이다사용자에게 여러분이 만든 버블정렬 컴포넌트를 판매한다고 가정한다면각 사용자를 위해 다른 프로그램을 만든다는 건 말이 안 되는 이야기 이다이럴 때 필요한 것이 바로 delegate!!
 
 
 
 
 
 
using System;
//우리가 배포하는 버블정렬 컴포넌트
class BubbleSorter
{
             //RunTime에 수행할 함수를 isConvert 라는 Delegate를 통해서 받는다.
             static public void Sort(object [] sortArray, CompareOp isConvert) //
              {
                            for (int i=0; i<sortArray.Length; i++)
                            {
                                         for (int j=0; j<i; j++)
                                         {
                                                      if (isConvert(sortArray[i], sortArray[j])) //
                                                       {
                                                                    object temp = sortArray[i];
                                                                    sortArray[i] = sortArray[j];
                                                                    sortArray[j] = temp;
                                                       }
                                         }
                            }
              }
}
 
//사용자 정의 클래스
class Employee
{
             private string name;
             private decimal salary;
 
             public Employee(string name, decimal salary)
             {
                           this.name = name;
                           this.salary = salary;
             }
 
             public override string ToString()
             {
                           return string.Format(name + ", {0:C}", salary);
             }
 
             //사용자 정의 클래스 비교 메서드
             public static bool isConvert(object obj1, object obj2) //
              {
                            Employee e1 = (Employee) obj1;
                            Employee e2 = (Employee) obj2;
                            return (e1.salary > e2.salary) ? true : false;
              }
}
 
delegate bool CompareOp (object lhs, object rhs);
 
class DelegateClass
{
             static void Main(string[] args)
             {
                           Employee [] employees =
                                                                  {
                                                                  new Employee("순돌이", 5000),
                                                                  new Employee("순딩이", 1500),
                                                             new Employee("차돌이", 3000),
                                                                  new Employee("공돌이",1000)
                                                                  };
                           CompareOp EmployeeCompareOp = new CompareOp(Employee.isConvert);
                           BubbleSorter.Sort(employees, EmployeeCompareOp);
 
                           for (int i=0; i<employees.Length; i++)
                                        Console.WriteLine(employees[i].ToString());
             }
}
 
 
 
①을 보시면 우리가 배포할 버블정렬 컴포넌트를 다시 편집한 것을 보실 수 있는데 , 컴포넌트는 두 개의 인자를 받는다첫번째는 정렬하게 될 object(모든 데이터 타입을 받을 수 있습니다. Object는 가장 상위클래스이기 때문이다.) 타입의 데이터이고두번 째 인자는 CompareOp delegate 이다다시 정리하면, object형 데이터와 delegate를 인자로 받는 버블정렬 컴포넌트 인 것이다.
 
②에서는 이전 소스코드에서 문제가 되었던 부분을 수정한 것으로 단지 숫자만 비교할 수 있게 만든 것이 아니라 delegate를 통해서 사용자 정의 비교 메서드를 호출하여 값을 비교하는 것이다여기서는 isConvert라는delegate를 사용하고 있는 것이다.
 
③은 사용자가 정의한 Employee라는 클래스를 비교하는 메서드
 
④에서는 CompareOp delegate가 ③에서 정의한 사용자 정의 비교 메서드를 참조하도록 하고 있다.
 
⑤에서는 employees라는 배열 데이터와 EmployeeCompareOp라는 delegate Sort() 메서드의 인자로 넘겨 정렬하고 있다.
 
위의 예제를 보시면이제 우리가 만든 버블정렬 컴포넌트는 어떤 상황에도 문제없이 사용될 수 있다는 것을 알 수 있다버블정렬 컴포넌트의 핵심기술(?)은 두 데이터의 값을 비교하는 것인데이 부분을 delegate로 바꿈으로써사용자가 정의할 수 있도록 만든 것이다그 만큼 컴포넌트 유연성 혹은 확장성이 확대된 것이다.
 
우리는 delegate도 배열로 선언되어 사용될 수 있음을 이전 예제에서 보았다하지만꼭 배열로 선언하지 않아도 하나의 delegate에 여러 개의 메서드를 넣을 수가 있는데 다음과 같이 쓸 수 있다.
 
delegate void DoubleOp(double value);
 
class MainEntryPoint
{
     static void Main(string[] args)
     {
          DoubleOp operations = new DoubleOp(MathOperations.MultiplyByTwo);
          operations += new DoubleOp(MathOperations.Square);
여러분이 원하시면다음과 같이 하는 것도 똑 같은 효과를 낸다.
 
DoubleOp operation1 = new DoubleOp(MathOperations.MultiplyByTwo);
DoubleOp operation2 = new DoubleOp(MathOperations.Square);
DoubleOp operations = operation1 + operation2;
 


 [진짜실무교육&환급100%]SQL/자바/스프링/안드로이드/닷넷C#/웹… 오라클자바…12-272362
 [채용예정교육]오라클자바개발잘하는신입뽑기2개월과정,교육전취…오라클자바…12-111710
53 [평일전액환급실무교육]Spring,자바&JSP,안드로이드,웹퍼블리싱,… 오라클자바…03-151524
52 [주말]C#,ASP.NET마스터 오라클자바…01-311632
51 [기업100%환급,평일주간]SQL기초에서스키마오브젝트,PLSQL,힌트… 오라클자바…01-312099
50 [평일주간야간,주말]C기본&자료구조,알고리즘 오라클자바…01-311285
49 [평일주간,평일야간,주말]Spring,MyBatis,Hibernate개발자과정 오라클자바…01-191592
48 [평일야간,주말]안드로이드개발자과정(Android기초실무) 오라클자바…01-111425
47 [평일야간,주말주간,주말야간]JAVA,Network&JSP&Spring,MyBatis,… 오라클자바…01-031962
46 [진짜실무교육&환급100%]SQL/자바/스프링/안드로이드/닷넷C#/웹… 오라클자바…12-272362
45 [기업100%환급]자바웹개발기초과정(JAVA,JDBC,JSP,Servlet,Aajx,… 오라클자바…12-191692
44 [평일주간야간, 주말]웹퍼블리싱 마스터(HTML5,CSS3,jQUERY,AJAX… 오라클자바…12-141667
43 [채용예정교육]오라클자바개발잘하는신입뽑기2개월과정,교육전취… 오라클자바…12-111710
42 [기업100%환급]웹퍼블리싱마스터(HTML5,CSS3,JavaScript,jQUERY) 오라클자바…12-091358
41 [평일야간]닷넷(C#,Network,ADO.NET,ASP.NET)마스터 오라클자바…12-011583
40 [기업100%환급]오라클&자바웹스프링신입과정3주(SQL,JAVA,JSP,Se… 오라클자바…12-011761
39 [평일야간,주말]SQL기초에서실무까지(SQL기초,PLSQL,힌트,튜닝) 오라클자바…12-011237

댓글 없음:

댓글 쓰기