2014년 10월 7일 화요일

[강좌#26]대리자(delegate)[닷넷C#교육/ADO.NET강좌/ASP.NET교육잘하는곳/C#,ASP.NET교육추천/닷넷실무교육/.NET,C#/ADO.NET교육/닷넷학원/ASP.NET실무교육]


대리자(delegate) 

델리게이트(Delegate)는 C의 함수 포인터와 비슷한 역할을 한다. 즉, 자기 자신이 실제로 하는 일은 없고, 단지 자기가 가리키고 있는 메서드(함수)를 호출하는 역할을 하는 것이다. 

결국 델리게이트(Delegate)는 함수에 대한 참조를 저장 하는 것인데 이렇게 함수에 대한 참조를 가리키고 있다는 것으로 인해 불가능한 작업등이 가능해진다. 예를 들면 Delegete를 다른 함수의 인자로 넘겨주게 되면 그 함수는 델리게이트가 보내 주는 함수의 참조를 이용하여 실행 시점에 호출될 함수를 결정 할 수 있는 것이다. 

대리자의 선언은 일반 함수의 선언과 비슷하나 함수 본문이 없고 delegate 라는 키워드를 사용한다는 점이 다르다. 델리게이트는 쓰레드와 이벤트에서 주로 이용 할 수 있다는 것은 참고로 알아 두자. 

아래의 코드를 보도록 하자… 

int i = int.Parse(“3746”); 

일반적으로 대부분의 메서드들이 인자 값을 받아 어떤 일 처리를 하게 된다. 위의 코드에서 Parse()메서드는 string형의 인자를 받아 int형으로 바꾸어 주는 역할을 하는데, 대부분의 메서드들이 인자를 받는 이유는 왜일까? 

메서드들이 인자를 받는 이유는 처리해야 할 값을 runtime시에만 알 수 있기 때문이다. 예를 들어 숫자를 정렬하는 메서드를 만들었다고 가정하자 사용자가 숫자 몇에서 몇까지를 정렬하기를 원하는지 알 수가 없다. 따라서, 나중에 그 값을 입력 받도록 처리 하기 위해 인자를 쓰게 되는 것이다. 
Delegate도 이와 같은 개념으로 생각하시면 되며 단지 다른 점이 있다면, value형인 매개변수 대신에 메서드를 인자로 받는다는 것이다. 그런데, 메서드를 인자로 받아야 할 상황들이 있을까요? 잠시 후, 예제를 보면 그런 상황들이 있다는 것을 알게 될 것이다. 

Delegate 선언 문법은 다음과 같다. 

①delegate ②void ③VoidOperation(④uint X); 

①은 delegate임을 선언, ②는 리턴형 ③은 delegate의 사용자 정의 ④는 입력 받는 인자의 형 및 변수 이다. 사용형식은 일반 메서드를 선언하는 것과 아주 흡사 한데 다른 점이 있다면 delegate라는 키워드를 먼저 쓰는 것과 구현부({ … })가 없다는 것이다. 구현부가 없는 이유는 이미 설명 드린 것과 같이 delegate 자신은 아무것도 하지 않고, 자신이 참조하고 있는 메서드(함수)만 호출해 주기 때문 이다. 
Delegate를 선언하는 것은 새로운 클래스를 생성하는 것과 같다. 형식은 데이터 타입처럼 쓰이지만, 실제로 System.Delegate 클래스에서 파생되는 새로운 객체를 생성한다. 


아래의 예제를 보자.[예제1] 
using System; 
public class Delegate1 

private delegate string GetString(); 

public static void Main(string[] args) 

int x = 30; 
GetString myMethod = new GetString(x.ToString); 
Console.WriteLine("문자열 : {0}", myMethod()); 



Delegate를 사용할 때 주의할 점은 delegate가 참조하는 메서드(여기서는 ToString) 의 인자 및 리턴형이 선언된 delegate와 같아야 한다는 것이다. 예제 1에서도 볼 수 있듯이, ToString() 메서드는 인자가 없고, string형을 리턴 한다. 따라서 선언된 delegate도 인자가 없이 string형을 리턴 하도록 선언되어 있지만 delegate는 참조하는 메서드가 어떤 타입이든상관 하지 않는다. static이든 메서드(함수) 객체이든 간에 관계없다. 즉, 참조하는 메서드의 인자형, 개수, 리턴 타입만 같으면 문제가 없다는 것 이다. 

[예제2] 
using System; 

class MathOperation 

public static double MultipleByTwo(double value) 

return value * 2; 


public static double Square(double value) 

return value * value; 



delegate double DoubleOp(double x); 

class DelegateTest2 

static void Main(string[] args) 

//Delegate를 배열로 지정 
DoubleOp[] operation = 

new DoubleOp(MathOperation.MultipleByTwo), 
new DoubleOp(MathOperation.Square) 
}; 

for(int i=0; i

Console.WriteLine("operation[{0}] 호출:", i); 
CallDelegate(operation[i], 5.0); //Delegate를 다른 메소드의 인자로 넘긴다. 
Console.WriteLine(); 



static void CallDelegate(DoubleOp func, double value) 

//넘겨받은 Delegate를 실행 한다. 
double ret = func(value); 
Console.WriteLine("입력된 값은 {0}이고 결과는 {1} 이다", value, ret); 



위의 예제에서 CallDelegate라는 메서드를 호출할 필요 없이 곧바로 delegate가 참조하는 메서드를 실행 하려면 다음과 같이하면 된다. 

operations[i](2.0); 

Delegate가 꼭 필요 한 경우 

아래와 같은 버블정렬이 있다고 하자. 

[예제3] 
for (int i=0; i

for (int j=0; j

①if (j > i) // 문제의 소지가 있는 부분 

int temp = sortArray[i]; // i 와 j 바꾸기 
sortArray[i] = sortArray[j]; 
sortArray[j] = temp; 




만약 이 버블정렬의 데이터가 위와 같은 숫자가 아니라 객체라면 어떻게 될까? 현재와 같은 구조에선 곤란하다. 이는 사용자가 어떤 식으로 클래스나 구조체 등을 정의해 놓았는지 알 수가 없기 때문이다. 사용자에게 여러분이 만든 버블정렬 컴포넌트를 판매한다고 가정한다면, 각 사용자를 위해 다른 프로그램을 만든다는 건 말이 안 되는 이야기 이다.이럴 때 필요한 것이 바로 delegate다!! 

[예제4] 
using System; 
//우리가 배포하는 버블정렬 컴포넌트 
class BubbleSorter 

//RunTime에 수행할 함수를 isConvert 라는 Delegate를 통해서 받는다. 
static public void Sort(object [] sortArray, CompareOp isConvert) //① 

for (int i=0; i

for (int j=0; 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
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%환급/오라클/자바/스프링/안드로이드/닷넷C#/웹퍼블리싱… 오라클자바…12-272100
 [채용예정교육]오라클자바개발잘하는신입뽑기2개월과정,교육전취…오라클자바…12-111520
53 [평일주간]100%환급6건,안드로이드,자바,C#,스프링3.2,SQL,힌트/… 오라클자바…03-151295
52 [기업100%환급]C#4.0,WinForm,ADO.NET프로그래밍 오라클자바…01-311430
51 [평일,기업100%환급]SQL기초에서 Schema Object까지 오라클자바…01-311377
50 [기업100%환급]Spring ,MyBatis,Hibernate실무과정(스프링개발자… 오라클자바…01-311118
49 [평일주간,평일야간,주말]Spring,MyBatis,Hibernate개발자과정 오라클자바…01-191439
48 [평일주간,평일야간,주말]안드로이드개발자과정 오라클자바…01-111266
47 [평일야간,주말주간,주말야간]JAVA,Network&JSP&Spring,MyBatis,… 오라클자바…01-031765
46 기업100%환급/오라클/자바/스프링/안드로이드/닷넷C#/웹퍼블리싱… 오라클자바…12-272100
45 [기업100%환급,평일주간]자바기초에서 JDBC, Servlet/JSP까지 오라클자바…12-191524
44 [평일야간, 주말]웹퍼블리싱 마스터(HTML5,CSS3,jQUERY,AJAX,Jav… 오라클자바…12-141503
43 [채용예정교육]오라클자바개발잘하는신입뽑기2개월과정,교육전취… 오라클자바…12-111520
42 [평일,기업100%환급]자바기초에서 JDBC, Servlet/JSP까지 오라클자바…12-091208
41 [평일야간, 주말]닷넷(C#,Network,ADO.NET,ASP.NET)마스터 오라클자바…12-011433
40 [기업100%환급]안드로이드개발자과정(Android전액환급교육) 오라클자바…12-011579
39 [평일야간,주말]SQL기초에서실무까지(SQL기초,PLSQL,힌트,튜닝) 오라클자바…12-011089

댓글 없음:

댓글 쓰기