학습내용
선문비트 21기
김동영
목 차
u Foreach
u Interface
u Collection
u Delegate
u Foreach문 이란?
배열 같은 여러 데이터 모음을 처음부터 끝까지 호출하여 처리 할 수 있다.
u Foreach문 사용예제
|
List<Man> mans; //제네릭 컬렉션
private SunBee() { … mans= new List<Man>(); … } private bool SetTutor(int num) { int men_count = 0,i=0; foreach (Man man in mans) { ITeach iteach = man as ITeach;// man을 ITeach로 형변환,실패시 null 리턴
if (iteach != null) { i++; if (num == i) { lr.SetTutor(man); mans.RemoveAt(men_count); return true; }
} men_count++; } return false; }
|
IEnumerable 인터페이스(Enumerator를 사용해 내부의 데이터를 순방향으로만 접근 할 수 있도록 지원)를 상속받으면, foreach문을 사용 할 수 있다. foreach문을 사용하여 맨처음부터 맨마지막 데이터까지 순차적으로 돌면서 접근 할 수 있다. 무조건 맨처음부터 맨 끝까지 이다.
u Interface란?
한마디로 인터페이스는 구현 약속이다. 인터페이스는 암시적 추상 클래스로 직접 인스턴스화 할 수 없다. 가장 특징적인 것은 인터페이스 정의 자체에서는 구현을 포함하지 않으면 인터페이스를 상속한 비추상 형식에서는 반드시 구현 해야한다.
u Interface 사용예제
|
interface ITeach { void Teach(); void Work(); } |
|
class Tea : ITeach { public void Teach()//미구현시 에러 { Console.WriteLine("열심히 강의 중"); } public void Work()//미구현시 에러 { Console.WriteLine("열심히 연구 중"); } } |
|
public static void main() { //ITeach iteach = new ITeach();// 에러: 인터페이스는 인스턴스를 만들 수 없습니다. Tea te = new Tea(); te.Teach(); te.Work(); } |
u Collection
데이터의 저장과 검색을 위해 특화된 클래스
Arry – 모든 배열의 기본 클래스
|
static void Main(string[] args) { int[] arr = new int[10]; int j = 0; for (int i = 10; i > 0; i--) { arr[j] = i; j++; } Array.Sort(arr);//정렬 foreach (int i in arr) { Console.WriteLine(i);
}
} |
ArrayList – 컨테이너 용량이 자동적으로 확장되는 Array
|
static void Main(string[] args) { ArrayList arr = new ArrayList();
for (int i = 10; i > 0; i--) { arr.Add(i); } //arr.Sort(); //정렬 arr.Remove(2); //삭제 foreach (int i in arr) { Console.WriteLine(i.ToString()); } } |
List – 제네릭 컬렉션으로 ArrayList와 동일하게 동작하지만 , Boxing 과정이 이뤄지지않는다.
|
class Program { static void Main(string[] args) { List<int> arr = new List<int>();
for (int i = 10; i > 0; i--) { arr.Add(i); } //arr.Sort(); arr.Remove(2); foreach (int i in arr) { Console.WriteLine(i.ToString());
} } } |
u Delegate
델리게이트란 콜백 함수 메커니즘을 제공한다. 콜백 메서드가 타입의 안전성이 있다고 보장해 주며, 여러 개의 메서드를 순서대로 실행하기 위한 기능을 제공하며, 인스턴스 메서드뿐아니라 정적 메서드의 호출도 지원한다.
|
Internal delegate int Feedback(int value1,int value2);
class Program { public int Add(int a, int b) { return a + b; } public static int Sub(int a, int b) { return a - b; } static void Main(string[] args) { Program pr = new Program(); Feedback fb = new Feedback(pr.Add); Feedback fb2 = new Feedback(Program.Sub);
Console.WriteLine(fb(1, 2)); Console.WriteLine(fb2(1, 2));
} } |
|
internal delegate void Feedback(int32 value); |
degate 키워드를 이용하여 델리게이트를 선언 하였을 때 내부적으로는 아래의 클래스를 정의한다.
|
internal class Feedback : System.MulticastDelegate { public Feedback(Object object1, IntPtr method);//생성자 public virtual void Invoke(Int32 value);//지정된 메서드와 동일한 프로토타입을 가지는 메서드
//비동기호출을 위한콜벡메서드 public virtual IAsyncResult BeginInvoke(Int32 value, AsyncCallback callback, Object object1); public virtual void EndInvoke(IAsyncResult result); } |
4개의 메서드를 가지고 있는데, 이중 Invoke 메서드는 위의 예제 중 Console.WriteLine(fb(1, 2)); 이부분이 내부적으로 Console.WriteLine(fb.Invoke(1, 2)); 이렇게 변하게 되는것이다. 실제로 이렇게 Invoke메서드를 호출하여도 된다.
모든 델리게이트 타입은 MulticastDelegate타입에서 파생되므로 MulticastDelegate타입의 모든 필드와 속성 및 메서드를 상속받는다. 이중 아래의 3개의 non-public 필드가 중요하다.
|
필드 |
타입 |
설명 |
|
_target |
System.object |
델리게이트 객체가 정적 메서드를 래핑 할 때 이 필드는 null이 되며, 델리게이트 객체가 인스턴스 메서드를 래핑할 때 이 필드는 콜백 메서드에 호출된 객체에 대한 참조를 가지게 된다. 즉 이필드는 인스턴스 메서드의 묵시적인 this매개 변수에 전달될 값을 갖는다. |
|
_methodPtr |
System.IntPtr |
CLR이 내부적으로 사용하는 콜백 메서드에 대한 포인터 |
|
_invocationList |
System.Object |
델리게이트 체인을 생성할 때 델리게이트의 배열을 참조한다. |
아까 위의 예제에서 인스턴스 메서드와 정적인 메서드를 Feedback 매개 변수에 넣어 주었는데, 정적인 메서드인 Sub의 필드 _target이 null이 된다. 인스턴스 메서드인 Add는 pr(Program 인스턴스)의 주소값이 _target에 대입된다.
델리게이트를 이용하여 다중 콜백 메서드 호출하기
델리게이트 체인 : 델리게이트 객체의 컬렉션이나 집합을 의미하며, 그 내부의 델리게이트 들에 의해 제공되는 모든 메서드를 실행하거나 호출할 수 있는 기능을 제공한다.
|
class Program { public void Hello() { Console.WriteLine("헬로"); } public static void Hi() { Console.WriteLine("하이"); } static void Main(string[] args) { Program pr = new Program(); Feedback fb = new Feedback(pr.Hello);//인스턴스 메서드 호출 Feedback fb2 = new Feedback(Program.Hi);//정적 메소드 호출 Feedback fb3 = fb + fb2; //Feedback fb3 = (Feedback)Feedback.Combine(fb, fb2); fb3();
} } |
Feedback 델리게이트 객체에 대한 참조 변수인 fb3는 콜백 메서드로 호출 될 수 있는 메서드들을 래핑하는 델리게이트 객체의 집합이나 체인을 참조한다.
Delegate클래스의 public 정적 메서드인 Combine메서드는 델리게이트를 체인에 추가 할 때 사용한다. 삭제로는 Feedback.Remove메서드가 있다.
|
Feedback fb3 = (Feedback)Feedback.Combine(fb, fb2); |
Invoke 메서드는 델리게이트 배열 내의 모든 요소들을 순환하여 Invoke 메서드를 호출하면 델리게이트 체인 내의 모든 델리게이트들이 호출된다. 헌데 이런 알고리즘은 다음과 같은 상황에서 문제가 발생한다. Fb3는 Add와 Sub 메서드를 호출하는데, Add메서드 리턴값은 무시되고 마지막에 호출된 Sub의 return 값만 갖게된다.
|
delegate int Feedback(int value1,int value2);
class Program { public int Add(int a, int b) { return a + b; } public static int Sub(int a, int b) { return a - b; } static void Main(string[] args) { Program pr = new Program(); Feedback fb1 = new Feedback(pr.Add); Feedback fb2 = new Feedback(Program.Sub); Feedback fb3 = fb1 + fb2; Console.WriteLine(fb3(1, 2));
} } |
이러한 문제로 MulticastDelegate 클래스는 GetInvocationList라는 인스턴스 메서드를 제공한다. 이 메서드를 이용하면 원하는 알고리즘에 따라 델리게이트 체인 내의 각각의 델리게이트를 호출 할 수 있다.
|
public abstract class MulticastDelegate : Delegate { public sealed override Delegate[] GetInvocationList(); } |
|
delegate int Feedback(int value1,int value2);
class Program { public int Add(int a, int b) { return a + b; } public static int Sub(int a, int b) { return a - b; } static void Main(string[] args) { Program pr = new Program(); Feedback fb1 = new Feedback(pr.Add); Feedback fb2 = new Feedback(Program.Sub); Feedback fb3 = fb1 + fb2;
Delegate []fbchain = fb3.GetInvocationList();//델리게이트 체인으로부터 델리게이트 배열을 얻어온다. foreach (Feedback fe in fbchain) { Console.WriteLine(fe(1, 2)); } } } |