필드
1. 필드는 클래스 또는 구조체 내부에 직접 선언되는 임의 형식의 변수입니다.
2. 필드는 포함하는 형식(containing type)의 형식입니다.
3. 클래스 또는 구조체는 인스턴스 필드 또는 정적 필드를 가지거나 둘 모두를 가질 수 있습니다.
4. 인스턴스 필드는 특정 형식의 인스턴스에 고유합니다(specific).
5. 인스턴스 필드 F를 포함하는 클래스 T가 있을 때 T 형식의 개체 두 개를 만드는 경우 다른 개체의 값에 영향을 주지 않고 각 개체의 F 값을 수정할 수 있습니다.
6. 이와 달리(By constrast) 정적 필드는 클래스 자체에 속해 있으며 해당 클래스의 모든 인스턴스에서 공유됩니다.
7. 인스턴스 A에서 정적 필드를 변경하는 경우 인스턴스 B와 C에서 이 필드에 액세스할 때 즉시 이 변경 내용을 볼 수 있습니다.
8. 일반적으로 액세스 가능성(accessibility)이 private 또는 protected인 변수에 대해서만 필드를 사용해야 합니다.
9. 클래스에서 클라이언트 코드에 노출하는 데이터는 메서드, 속성, 인덱서를 통해 제공해야 합니다
10. 내부 필드에 간접적으로 액세스하기 위해 이러한 구문(constructs)을 사용함으로써 잘못된 입력 값으로부터 보호(guard against)할 수 있습니다.
11. public 속성에 의해 노출되는 데이터를 저장하는 private 필드를 지원 저장소(backing store) 또는 지원 필드(backing field)라고 합니다.
12. 대개(typically) 필드에는 여러 클래스 메서드에서 액세스해야 하고 단일 메서드의 수명(lifetime)보다 오래 저장되어야 하는 데이터가 저장됩니다.
13. 예를 들어 달력 데이터를 나타내는 클래스에는 각각, 일, 월, 년을 나타내는 세 개의 정수 필드가 포함될 수 있습니다.
14. 단일 메서드 범위 밖에서 사용하지 않는 변수는 메서드 본문의 내부에서 지역 변수로 선언해야 합니다.
15. 필드는 필드의 액세스 수준을 지정하고 필드의 형식과 필드의 이름을 차례로 사용하여 클래스 블록에서 선언됩니다.
public class CalendarEntry { // private field private DateTime date; // public field (Generally not recommended.) public string day; // Public property exposes date field safely. public DateTime Date { get { return date; } set { // Set some reasonable boundaries for likely birth dates. if (value.Year > 1900 && value.Year <= DateTime.Today.Year) { date = value; } else throw new ArgumentOutOfRangeException(); } } // Public method also exposes date field safely. // Example call: birthday.SetDate("1975, 6, 30"); public void SetDate(string dateString) { DateTime dt = Convert.ToDateTime(dateString); // Set some reasonable boundaries for likely birth dates. if (dt.Year > 1900 && dt.Year <= DateTime.Today.Year) { date = dt; } else throw new ArgumentOutOfRangeException(); } public TimeSpan GetTimeSpan(string dateString) { DateTime dt = Convert.ToDateTime(dateString); if (dt != null && dt.Ticks < date.Ticks) { return date - dt; } else throw new ArgumentOutOfRangeException(); } }
16. 개체의 필드에 액세스하려면 objectname.fieldname과 같이 개체 이름 뒤에 마침표(period)와 필드 이름을 추가합니다.
CalendarEntry birthday = new CalendarEntry(); birthday.day = "Saturday";
17. 필드를 선언할 때 대입 연산자를 사용하여 필드의 초기 값을 지정할 수 있습니다.
18. 예를 들어 day 필드에 "Monday"을 자동으로 할당하려면 다음 예제와 같이 day를 선언합니다.
public class CalendarDateWithInitialization { public string day = "Monday"; //... }
19. 필드는 개체 인스턴스의 생성자를 호출하기 직전에 초기화됩니다.
20. 생성자가 필드의 값을 할당하는 경우 필드 선언 도중 지정된 모든 값을 덮어씁니다.
21. 자세한 내용은 생성자 사용을 참조하십시오.
![]() |
---|
필드 이니셜라이저는 다른 인스턴스 필드를 참조할 수 없습니다. |
22. 필드는 public, private, protected, internal, protected internal로 표시할 수 있습니다.
23. 이러한 액세스 한정자는 클래스 사용자가 필드에 액세스하는 방식을 정의합니다.
24. 자세한 내용은 액세스 한정자를 참조하십시오.
25. 추가적으로(optionally) 필드를 static으로 선언할 수도 있습니다.
26. 이렇게 하면 클래스의 인스턴스가 없어도 언제든지(at any time) 호출자가 필드를 사용할 수 있습니다.
27. 자세한 내용은 정적 클래스 및 정적 클래스 멤버를 참조하십시오.
28. readonly를 사용하여 필드를 선언할 수 있습니다.
29. 읽기 전용 필드에는 초기화 도중이나 생성자에서만 값을 할당할 수 있습니다.
30. static readonly 필드는 상수와 매우 비슷하지만 C# 컴파일러가 컴파일 타임이 아닌 런타임에만 정적 읽기 전용 필드의 값에 액세스할 수 있다는 점에서 차이가 있습니다.
31. 자세한 내용은 상수를 참조하십시오.
람다 식
1. 람다 식은 대리자 또는 식 트리 형식을 만드는 데 사용할 수 있는 익명 함수입니다.
2. 람다 식을 사용하여 인수로 전달되거나 함수 호출 값으로 반환되는 로컬 함수를 쓸 수 있습니다.
3. 람다 식은 LINQ 쿼리 식을 작성하는 데 특히(particularly) 유용합니다.
4. 람다 식을 만들려면 람다 연산자 => 왼쪽에 입력 매개 변수를 지정하고(있는 경우(if any)) 다른 쪽에(on the other side) 식이나 문 블록을 삽입합니다.
5. 예를 들어 람다 식 x => x * x는 이름이 x인 매개 변수를 지정하고 x 제곱 값(x squared)을 반환합니다.
6. 다음 예제와 같이 대리자 형식에 이 식을 할당할 수도 있습니다.
delegate int del(int i); static void Main(string[] args) { del myDelegate = x => x * x; int j = myDelegate(5); //j = 25 }
7. 식 트리 형식을 만들려면
using System.Linq.Expressions; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { Expression<del> myET = x => x * x; } } }
8. => 연산자는 할당(=)과 우선 순위(precedence)가 같고 오른쪽 결합성(right associative)이 있습니다.(연산자 문서의 "결합성" 단원 참조)
9. 람다 식은 메서드 기반 LINQ 쿼리에서 Where<TSource> 같은 표준 쿼리 연산자 메서드의 인수로 사용됩니다.
10. Where<TSource> to Objects 및 Enumerable에서처럼 메서드 기반의 구문을 사용하여 LINQ 클래스에서 LINQ to 메서드를 호출하는 경우 매개 변수는 System.Func<T, TResult> 대리자 형식입니다.
11. 람다 식은 이러한 대리자를 만드는 가장 간단한 방법(the most convenient way)입니다.
12. 예를 들어 System.Linq.Queryable에서처럼 이 메서드를 LINQ to SQL 클래스에서 호출하는 경우 매개 변수 형식은 System.Linq.Expressions.Expression<Func>이고, 여기서 Func는 입력 매개 변수를 16개까지 가질 수 잇는 임의의 Func 대리자입니다
13. 이 경우에도 람다 식을 사용하면 식 트리를 간단하게(a very concise way) 만들 수 있습니다.
14. 람다 식은 Where 호출과 비슷하게 보일 수 있지만 실제로 람다 식을 통해 생성되는 개체 형식은 다릅니다.
15. 위의 예제에서 대리자 시그니처는 형식이 암시적으로 지정된 int 형식의 입력 매개 변수 하나를 포함하는 int를 반환합니다.
16. 람다 식에도 입력 매개 변수 하나(x)와 컴파일러에서 int 형식으로 암시적으로 변환할 수 있는 반환 값이 있기 때문에 람다 식을 이 형식의 대리자로 변환할 수 있습니다.
17. 형식 유추(type inference)는 다음 단원에서 자세하게 설명합니다.
18. 입력 매개 변수를 5로 사용하여 대리자를 호출하면 25라는 결과가 반환됩니다.
19. is 또는 as 연산자의 왼쪽에는 람다 식을 사용할 수 없습니다.
20. 무명 메서드에 적용되는 모든 제한(All restrictions)은 람다 식에도 적용됩니다.
21. 자세한 내용은 무명 메서드를 참조하세요.
<식 람다>
22. => 연산자의 오른쪽에 식이 있는 람다 식을 식 람다라고 합니다.
23. 식 람다는 식 트리를 만드는 데 광범위하게(extensively) 사용됩니다.
24. 식 람다는 식의 결과를 반환하여 기본 형식은 다음과 같습니다.
(input parameters) => expression
25. 괄호(the parentheses)는 람다 식에 입력 매개 변수가 하나뿐인 경우에만 생략할 수 있고, 그렇지 않으면 생략할 수 없습니다.
26. 둘 이상의 입력 매개 변수는 다음과 같이 괄호로 묶고 쉽표로 구분해야 합니다.
(x, y) => x == y
27. 컴파일러에서 입력 형식을 유추할 수 없는 경우도 있습니다.
28. 이와 같은 경우에는 다음 예제와 같이 형식을 명시적으로 지정할 수 있습니다.
(int x, string s) => s.Length > x
28. 입력 매개 변수가 0개이면 다음과 같이 빈 괄호를 지정합니다.
() => SomeMethod()
29. 위의 예제에서 식 람다의 본문은 메서드 호출로 구성될 수 있습니다.
30. 하지만 SQL Server와 같은 >NET Framework 외부에서 평가되는 식 트리를 만드는 경우에는 람다 식에 메서드 호출을 사용하지 않아야 합니다.
31. 이러한 메서드는 .NET 공용 언어 런타임의 컨텍스트 안에서만 의미가 있습니다.
<문 람다>
32. 문 람다는 다음과 같이 중괄호(braces) 안에 문을 지정한다는 점을 제외하면 식 람다와 비슷합니다(resemble).
(input parameters) => {statement;}
33. 문 람다의 본문에 지정할 수 있는 문의 개수에는 제한이 없지만(any number of statements) 일반적으로(in practice) 2-3개 정도만 지정합니다.
delegate void TestDelegate(string s); … TestDelegate myDel = n => { string s = n + " " + "World"; Console.WriteLine(s); }; myDel("Hello");
34. 무명 메서드와 마찬가지로 문 람다는 식 트리를 만드는 데 사용할 수 없습니다.
<비동기 람다>
35. async 및 await 키워드를 사용하여 비동기 처리(asynchronous processing)를 통합하는(incorporate) 람다 식과 문을 쉽게 만들 수 있습니다.
36. 예를 들어 다음 Windows Forms 에제에는 비동기 메서드 ExampleMethodAsync를 호출하고 기다리는 이벤트 처리기가 포함되어 있습니다.
public partial class Form1 : Form { public Form1() { InitializeComponent(); } private async void button1_Click(object sender, EventArgs e) { // ExampleMethodAsync returns a Task. await ExampleMethodAsync(); textBox1.Text += "\r\nControl returned to Click event handler.\r\n"; } async Task ExampleMethodAsync() { // The following line simulates a task-returning asynchronous process. await Task.Delay(1000); } }
37. 비동기 람다를 사용하여 동일한 이벤트 처리기를 추가할 수 있습니다.
38. 이 처리기를 추가하려면 다음 예제에 표시된 것처럼 람다 매개 변수 목록에 async 한정자를 추가합니다.
public partial class Form1 : Form { public Form1() { InitializeComponent(); button1.Click += async (sender, e) => { // ExampleMethodAsync returns a Task. await ExampleMethodAsync(); textBox1.Text += "\r\nControl returned to Click event handler.\r\n"; }; } async Task ExampleMethodAsync() { // The following line simulates a task-returning asynchronous process. await Task.Delay(1000); } }
39. 비동기 메서드를 만들고 사용하는 방법에 대한 자세한 내용은 Async 및 Await를 사용한 비동기 프로그래밍을 참조하세요.
<표준 쿼리 연산자와 람다 식>
40. 대부분의 표준 쿼리 연산자에는 형식이 제네릭 대리자의 Func<T, TResult> 패밀리 중 하나인 입력 매개 변수를 사용합니다.
41. 이러한 대리자는 형식 매개 변수를 사용하여 입력 매개 변수의 수와 형식 및 대리자의 반환 형식을정의합니다.
42. Func 대리자는 소스 데이터 집합에 있는 각 요소에 적용할 사용자 정의 식을 캡슐화하는 데 매우 유용합니다.
43. 다음 대리자 형식을 예로 들 수 있습니다.
public delegate TResult Func<TArg0, TResult>(TArg0 arg0)
44. 이 경우 대리자를 Func<int, bool> myFunc로 인스턴스화할 수 있습니다.
45. 여기서 int는 입력 매개 변수이고, bool은 반환 값입니다
46. 반환 값은 항상 마지막 형식 매개 변수에 지정됩니다.
47. Func<int, string, bool>은 두 입력 매개 변수 int, string와 반환 형식 bool을 사용하여 대리자를 정의합니다.
48. 다음 Func 대리자를 호출하면 입력 매개 변수가 5인지 여부를 나타내는 true 또는 false가 반환됩니다.
Func<int, bool> myFunc = x => x == 5; bool result = myFunc(4); // returns false of course
49. System.Linq.Queryable에 정의되어 있는 표준 쿼리 연산자의 경우와 같이 인수 형식이 Expression<Func>인 경우에도 람다 식을 사용할 수 있습니다.
50. Expression<Func> 인수를 지정하면 식 트리에 람다 식이 컴파일됩니다.
51. 다음 코드에서는 표준 쿼리 연산자인 Count<TSource> 메서드를 보여 줍니다.
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; int oddNumbers = numbers.Count(n => n % 2 == 1);
52. 컴파일러에서 입력 매개 변수의 형식을 유추하거나 사용자가 형식을 명시적으로 지정할 수 있습니다
53. 이 람다 식은 2로 나누었을 때 나머지(remainder)가 1인 정수(n)의 수를 계산합니다.
54. 다음 코드 줄은 숫자 시퀀스에서 조건을 만족하지 않는 첫 번째 숫자가 "9"이기 때문에 numbers 배열에서 "9" 왼쪽에 있는 모든 요소가 포함된 시퀀스를 생성합니다.
var firstNumbersLessThan6 = numbers.TakeWhile(n => n < 6);
55. 이 예제에서는 괄호로 묶어 입력 매개 변수를 여러 개 지정하는 방법을 보여 줍니다.
56. 이 메서드는 값이 해당 위치보다 작은 숫자를 발견할 때까지(is encountered) 숫자 배열의 모든 요소를 반환합니다.
57. 여기서 람다 연산자(=>)를 크거나 같은 연산자(>=)와 혼동하면 안 됩니다.
var firstSmallNumbers = numbers.TakeWhile((n, index) => n >= index);
<람다 식에서의 형식 유추>
58. 컴파일러에서 람다 식 본문, 매개 변수의 대리자 형식 및 C# 언어 사양에 설명되어 있는 기타 요소를 기준으로 형식을 유추할 수 있기 때문에 대부분의 경우에는 람다 식을 작성할 때 입력 매개 변수의 형식을 지정하지 않아도 됩니다.
59. 대부분의 표준 쿼리 연산자에서 첫 번째 입력 형식은 소스 시퀀스 요소의 형식입니다.
60. 따라서 IEnumerable<Customer>를 쿼리할 경우 입력 변수가 Customer 개체로 유추됩니다.
customers.Where(c => c.City == "London");
61. 람다 식에는 다음과 같은 일반적인 규칙이 적용됩니다.
1) 람다 식과 대리자 형식에 포함된 매개 변수 수가 같아야 합니다.
2) 람다 식의 각 입력 매개 변수는 해당되는 대리자 매개 변수로 암시적으로 변환될 수 있어야 합니다.
3) 람다 식의 반환 값(있는 경우)은 대리자의 반환형식으로 암시적으로 변환될 수 있어야 합니다.
62. 공용 형식 시스템에는 "람다 식"이라는 개념이 기본적으로(intrinsic) 포함되어 있지 않기 때문에 람다 식 자체에는 형식이 없습니다.
63. 그러나 람다 식의 "형식"을 비공식적으로(informally) 언급해야 할 경우도 있는데 이 경우 형식은 대리자 형식 또는 람다 식이 변환되는 Expression 형식을 의미합니다.
64. 이 경우 형식은 대리자 형식 또는 람다 식이 변환되는 Expression 형식을 의미합니다.
<람다 식의 변수 범위>
65. 람다 식은 람다 함수를 정의하는 메서드 범위 내에 있거나 람다 식을 포함하는 형식 범위 내에 있는 외부 변수(outer variables)(무명 메서드 참조)를 참조할 수 있습니다.
66. 이러한 방식으로 캡처되는 변수는 볌수가 범위를 벗어나 가비지 수집되는 경우에도 람다 식에 사용할 수 있도록 저장됩니다.
67. 외부 변수는 명확하게(definitely) 할당해야만 람다 식에 사용(consume)할 수 있습니다.
68. 다음 예제에서는 이러한 규칙을 보여 줍니다.
delegate bool D(); delegate bool D2(int i); class Test { D del; D2 del2; public void TestMethod(int input) { int j = 0; // Initialize the delegates with lambda expressions. // Note access to 2 outer variables. // del will be invoked within this method. del = () => { j = 10; return j > input; }; // del2 will be invoked after TestMethod goes out of scope. del2 = (x) => {return x == j; }; // Demonstrate value of j: // Output: j = 0 // The delegate has not been invoked yet. Console.WriteLine("j = {0}", j); // Invoke the delegate. bool boolResult = del(); // Output: j = 10 b = True Console.WriteLine("j = {0}. b = {1}", j, boolResult); } static void Main() { Test test = new Test(); test.TestMethod(5); // Prove that del2 still has a copy of // local variable j from TestMethod. bool result = test.del2(10); // Output: True Console.WriteLine(result); Console.ReadKey(); } }
69. 람다 식의 변수 범위에는 다음과 같은 규칙이 적용됩니다.
1) 캡처된 변수는 해당 변수를 참조하는 대리자가 가비지 수집 대상이 될 때까지 가비지 수집되지 않습니다.
2) 람다 식에 사용된 변수는 외부 메서드에 표시되지 않습니다.
3) 람다 식은 바깥쪽 메서드(an enclosing method)에서 ref 또는 out 매개 변수를 직접 캡처할 수 없습니다.
4) 람다 식의 return 문에 의해서는 바깥쪽 메서드가 반환되지 않습니다.
5) 점프문의 대상이 블록 외부에 있는 경우 람다 식에 람다 함수 내에 있는 goto 문, break 문, continue 문을 포함할 수 없습니다.
6) 대상이 블록 내에 있는 경우 람다 함수 블록 외부에 점프문을 사용해도 오류가 발생합니다.
무명 메서드 (anonymous methods)
1. 2.0보다 이전 버전의 C#에서는 명명된 메서드를 사용하는 방법으로만 대리자를 선언할 수 있었습니다.
2. C# 2.0에는 무명 메서드가 도입되었고 C# 3.0 이상에서는 무명 메서드 대신 람다 식을 사용하여 인라인 코드를 작성하는 방법이 더 선호됩니다(supercede).
3. 그러나 이 항목에서 설명하는 무명 메서드에 대한 내용은 람다 식에도 적용됩니다.
4. 무명 메서드에는 람다 식에 없는 기능이 한 가지 있습니다.
5. 무명 메서드를 사용하면 매개 변수 목록을 생략할 수 있으며, 이는 무명 메서드가 여러 시그니처를 가진 대리자로 변환될 수 있음을 의미합니다.
6. 람다 식을사용해서는 이렇게 할 수 없습니다.
7. 람다 식에 대한 자세한 내용은 람다 식을 참조하십시오.
8. 무명 메서드를 만드는 것은 본질적으로(essentially) 코드 블록을 대리자 매개 변수로 전달하기 위한 방법입니다.
// Create a handler for a click event. button1.Click += delegate(System.Object o, System.EventArgs e) { System.Windows.Forms.MessageBox.Show("Click!"); };
// Create a delegate. delegate void Del(int x); // Instantiate the delegate using an anonymous method. Del d = delegate(int k) { /* ... */ };
9. 무명 메서드를 사용하면 별도의 메서드를 만들 필요가 없으므로 대리자를 인스턴스화하는 데 따르는 코딩 오버헤드를 줄일 수 있습니다.
10. 예를 들어 메서드를 만드는 것이 불필요한 오버헤드(an unnecessary overhead)가 되는 상황에서는 대리자 대신 코드 블록을 지정하는 것이 유용합니다.
11. 새로운 스레드를 시작할 때가 좋은 예입니다.
12. 다음 클래스는 스레드를 만들고 스레드에서 실행할 코드가 포함하므로 대리자를 위한 추가 메서드를 만들 필요가 없습니다.
void StartThread() { System.Threading.Thread t1 = new System.Threading.Thread (delegate() { System.Console.Write("Hello, "); System.Console.WriteLine("World!"); }); t1.Start(); }
13. 무명 메서드의 매개 변수 범위는 무명 메서드 블록입니다.
14. 무명 메서드 블록 안에서 블록 밖을 대상으로 goto, break, continue와 같은 점프 문을 사용하면 오류가 발생합니다.
15. 무명 메서드 블록 밖에서 블록 안을 대상으로 goto, break, continue와 같은 점프 문을 사용해도 오류가 발생합니다.
16. 지역 변수 및 매개 변수의 범위에 무명 메서드 선언이 포함되는 경우 이러한 변수를 무명 메서드의 외부 변수라고 합니다.
17. 예를 들어 다음 코드 단편(segment)에서 n은 외부 변수(an outer variable)입니다.
int n = 0; Del d = delegate() { System.Console.WriteLine("Copy #:{0}", ++n); };
18. 외부 변수에 n 이라고 캡처 대리자를 만들 때 무명 메서드를 참조하는 대리자가 가비지 수집의 대상이 될 때까지 지역 변수와 달리 캡처된 변수의 수명은 확장합니다.
19. 무명 메서드에서는 외부 범위의 ref 또는 out 매개 변수에 액세스할 수 없습니다.
20. 무명 메서드 블록에서는 unsafe 코드는 액세스되지 않습니다.
21. 무명 메서드 is 연산자의 왼쪽에 사용할 수 없습니다.
<예제>
22. 다음 예제에서는 대리자를 인스턴스화하는 두 가지 방법을 보여 줍니다.
1) 대리자를 무명 메서드에 연결(Associating the delegate with an anonymous method).
2) 대리자를 명명된메서드(DoWork)에 연결(Associating the delegate with a named method (DoWork).
23. 각각의 경우에서(In each case) 대리자가 호출되면 메시지가 표시됩니다.
// Declare a delegate. delegate void Printer(string s); class TestClass { static void Main() { // Instantiate the delegate type using an anonymous method. Printer p = delegate(string j) { System.Console.WriteLine(j); }; // Results from the anonymous delegate call. p("The delegate using the anonymous method is called."); // The delegate instantiation using a named method "DoWork". p = new Printer(TestClass.DoWork); // Results from the old style delegate call. p("The delegate using the named method is called."); } // The method associated with the named delegate. static void DoWork(string k) { System.Console.WriteLine(k); } } /* Output: The delegate using the anonymous method is called. The delegate using the named method is called. */
명명된 메서드와 무명 메서드의 대리자 비교
1. 대리자를 명명된 메서드에 연결할 수 있습니다.
2. 명명된 메서드를 사용하여 대리자를 인스턴스화하는 경우 다음과 같이 메서드를 매개 변수로 전달합니다.
// Declare a delegate: delegate void Del(int x); // Define a named method: void DoWork(int k) { /* ... */ } // Instantiate the delegate using the method as a parameter: Del d = obj.DoWork;
3. 이를 명명된 메서드 사용이라고 합니다.
4. 명명된 메서드를 사용하여 만든 대리자에서는 정적 메서드나 인스턴스 메서드를 캡슐화할 수 있습니다.
5. 이전 버전의 C#에서 대리자를 인스턴스화하는 유일한 방법은 명명된 메서드를 사용하는 것입니다.
6. 그러나 새 메서드를 만들어 예기치 못한 부담이 생기능 경우를 대비하여, C#에서는 대리자를 호출할 때 처리될 코드 대리자를 인스턴스화할 때 바로 지정할 수 있도록 허용합니다.
7. 블록에는 람다 식 또는 무명 메서드가 포함될 수 있습니다.
8. 자세한 내용은 익명 함수를 참조하십시오.
9. 대리자 매개 변수로 전달하는 메서드의 시그니처는 대리자 선언의 시그니처와 동일해야 합니다.
10. 대리자 인스턴스는 정적 또는 인스턴스 메서드를 캡슐화할 수 있습니다.
11. 대리자에서는 out 매개 변수를 사용할 수 있지만, 호출된 대리자를 알 수 없으므로 멀티캐스트 이벤트 대리자에는 이 매개 변수를 사용하지 않는 것이 좋습니다.
12. 다음은 대리자 선언 및 사용에 대한 간단한 예제입니다.
13. 대리자 Del의 시그니처와 연결된 메서드 MultiplyNumbers의 시그니처는 동일합니다.
// Declare a delegate delegate void Del(int i, double j); class MathClass { static void Main() { MathClass m = new MathClass(); // Delegate instantiation using "MultiplyNumbers" Del d = m.MultiplyNumbers; // Invoke the delegate object. System.Console.WriteLine("Invoking the delegate using 'MultiplyNumbers':"); for (int i = 1; i <= 5; i++) { d(i, 2); } // Keep the console window open in debug mode. System.Console.WriteLine("Press any key to exit."); System.Console.ReadKey(); } // Declare the associated method. void MultiplyNumbers(int m, double n) { System.Console.Write(m * n + " "); } } /* Output: Invoking the delegate using 'MultiplyNumbers': 2 4 6 8 10 */
14. 다음 예제에서는 하나의 대리자를 정적 메서드와 인스턴스 메서드 모두에 매핑하고 각 메서드에서 특정 정보를 반환합니다.
// Declare a delegate delegate void Del(); class SampleClass { public void InstanceMethod() { System.Console.WriteLine("A message from the instance method."); } static public void StaticMethod() { System.Console.WriteLine("A message from the static method."); } } class TestSampleClass { static void Main() { SampleClass sc = new SampleClass(); // Map the delegate to the instance method: Del d = sc.InstanceMethod; d(); // Map to the static method: d = SampleClass.StaticMethod; d(); } } /* Output: A message from the instance method. A message from the static method. */
익명 함수
1. 익명 함수는 대리자 형식과 함께 사용될 수 있는 "인라인 문"이나 식입니다.
2. 익명 함수는 명명된 대리자를 초기화하는 데 사용되거나 명명된 대리자 형식 대신 메서드 매개 변수로 전달될 수 있습니다.
3. 익명 함수에는 두 가지 종류가 있으며 각 익명 함수는 다음 단원에서 따로 설명합니다.
1) 람다 식
2) 무명 메서드
![]() |
---|
람다 식은 식 트리뿐만 아니라 대리자에도 바인딩할 수 있습니다. |
<C#에서의 대리자 발전 과정>
4. C# 1.0에서는 코드의 다른 부분에 정의된 메서드를 통해 명시적으로 초기화하는 방법으로 대리자의 인스턴스를 만들었습니다.
5. C# 2.0에서는 대리자 호출 시 실행될 수 있는 무명의 인라인 문 블록을 작성하기 위한 방법으로 무명 메서드라는 개념이 도입되었습니다.
6. C# 3.0에서는 무명 메서드와 비슷한 개념이지만 표현력이 뛰어나면서 간결한(concise) 람다 식이 도입되었습니다.
7. 이러한 두 기능(features)을 통칭하여(collectively) 익명 함수라고 합니다.
8. 일반적으로 .NET Framework 3.5 이상을 대상으로 하는 응용 프로그램에서는 람다 식을 사용하는 것이 좋습니다.
9. 다음 예제에서는 C# 1.0부터 C# 3.0까지 대리자 생성의 발전 과정을 보여 줍니다.
class Test { delegate void TestDelegate(string s); static void M(string s) { Console.WriteLine(s); } static void Main(string[] args) { // Original delegate syntax required // initialization with a named method. TestDelegate testDelA = new TestDelegate(M); // C# 2.0: A delegate can be initialized with // inline code, called an "anonymous method." This // method takes a string as an input parameter. TestDelegate testDelB = delegate(string s) { Console.WriteLine(s); }; // C# 3.0. A delegate can be initialized with // a lambda expression. The lambda also takes a string // as an input parameter (x). The type of x is inferred by the compiler. TestDelegate testDelC = (x) => { Console.WriteLine(x); }; // Invoke the delegates. testDelA("Hello. My name is M and I write lines."); testDelB("That's nothing. I'm anonymous and "); testDelC("I'm a famous author."); // Keep console window open in debug mode. Console.WriteLine("Press any key to exit."); Console.ReadKey(); } } /* Output: Hello. My name is M and I write lines. That's nothing. I'm anonymous and I'm a famous author. Press any key to exit. */
'프로그래밍 > C#' 카테고리의 다른 글
보간된 문자열(Interpolated strings) (0) | 2016.06.14 |
---|---|
제네릭 (0) | 2016.06.11 |
C# 컨텍스트 키워드 (0) | 2016.06.06 |
C# 키워드 T~Z (0) | 2016.06.03 |
C# 키워드 O~S (0) | 2016.05.31 |