달력

5

« 2024/5 »

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
2016. 6. 10. 19:46

C# 기타 프로그래밍/C#2016. 6. 10. 19:46

필드


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. 자세한 내용은 생성자 사용을 참조하십시오.

System_CAPS_note참고

필드 이니셜라이저는 다른 인스턴스 필드를 참조할 수 없습니다.

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) 무명 메서드

System_CAPS_note참고

람다 식은 식 트리뿐만 아니라 대리자에도 바인딩할 수 있습니다.

<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
:
Posted by 지훈2
2016. 6. 6. 17:36

C# 컨텍스트 키워드 프로그래밍/C#2016. 6. 6. 17:36

add

 

1. add 컨텍스트 키워드(the add contextual keyword)는 클라이언트 코드가 사용자의 이벤트를 구독(subscribe)할 때 호출되는 사용자 지정 이벤트 접근자(a custom event accessor)를 정의하는데 사용됩니다.

2. 사용자 지정 add 접근자를 제공하는 경우에는 remove 접근자도 제공해야 합니다.

3. add 접근자 를 제공(supply)하는 경우에는 remove 접근자도 제공해야 합니다.

4. 다음 예제에서는 사용자 지어 add 및 remove 접근자가 있는 이벤트를 보여 줍니다.

5. 전체 예제를 보려면 방법: 인터페이스 이벤트 구현을 참조하십시오.

 

class Events : IDrawingObject
{
    event EventHandler PreDrawEvent;

    event EventHandler IDrawingObject.OnDraw
    {
        add
        {
            lock (PreDrawEvent)
            {
                PreDrawEvent += value;
            }
        }
        remove
        {
            lock (PreDrawEvent)
            {
                PreDrawEvent -= value;
            }
        }
    }

}

 

6. 일반적으로 자체 사용자 지정 이벤트 접근자를 제공할 필요는 없습니다.

7. 대부분의 경우 이벤트를 선언할 때 컴파일러에서 자동으로 생성되는 접근자로도 충분합니다.

 

 

 


 

extern alias

 

1. 정규화된 형식 이름이 동일하고 버전만 다른 두 개의 어셈블리를 참조해야 할 수도 있습니다.

2. 예를 들어 동일한 응용 프로그램에서 어셈블리의 버전을 여러 개 사용해야 할 수도 있습니다

3. 외부 어셈블리 별칭을 사용하면 각 어셈블리의 네임스페이스가 별칭으로 명명되어 루트 수준 네임스페이스 안에 래핑(wrapped)되므로 동일한 파일에서 여러 어셈블리 버전을 사용할 수 있습니다.

System_CAPS_note참고

extern 키워드는 메서드 한정자로도 사용되어 비관리 코드로 작성된 메서드를 선언합니다.

4. 정규화된 형식 이름이 동일한 두 개의 어셈블리를 참조하려면 다음과 같이 명령 프롬프트에서 별칭을 지정해야 합니다.

 

/r:GridV1=grid.dll

 

/r:GridV2=grid20.dll

 

5. 이렇게 하면 외부 별칭 GridV1 및 GridV2가 만들어집니다.

6. 이러한 별칭을 한 프로그램에서 사용하려면 extern 키워드를 사용하여 별칭을 참조합니다.

 

extern alias GridV1;

 

extern alias GridV2;

 

7. 각 외부 별칭 선언에서는 전역 네임스페이스와 같은 수준(하위 수준은 제외)에 있는 추가 루트 수준 네임스페이스를 선언(introduce)합니다.

8. 따라서(Thus) 정규화된 이름을 사용하지 않고도 적절한 네임스페이스 별칭을 루트로 하여 모호성 문제 없이(without ambiguity) 각 어셈블리의 형식을 참조할 수 있습니다.

9. 앞의 예제에서 GridV1::Grid는 Grid.dll의 그리드 컨트롤이며 GridV2::Grid는 grid20.dll의 그리드 컨트롤입니다.

 

 

 


 

ascending


1. ascending 컨텍스트 키워드는 쿼리 식의 orderby 절(the orderby clause)에서 사용되어 정렬 순서(the sort order)를 오름차순(from smallest to largest)으로 지정합니다. 

2. ascending은 기본 정렬 순서이므로 지정할 필요가 없습니다.

3. 다음 예제에서는 orderby 절에서 ascending을 사용하는 방법을 보여 줍니다.


IEnumerable<string> sortAscendingQuery =
    from vegetable in vegetables
    orderby vegetable ascending
    select vegetable;





async


1. async 한정자를 사용하여 메서드, 람다 식, 무명 메서드를 비동기(asynchronous)로 지정합니다.

2. 메서드 또는 식에 이 한정자를 사용하면 비동기 메서드라고 합니다.


public async Task<int> ExampleMethodAsync()
{
    // . . . .
}


3. 비동기 프로그래밍이 처음이거나 비동기 메서드가 await 키워드를 사용하여 호출자의 스레드를 차단(block)하지 않고 장기 실행 작업(potentially long-running work)을 수행할 수 있는 방법을 모르는 경우 Async 및 Await를 사용한 비동기 프로그래밍의 지침을 읽어야 합니다.


string contents = await contentsTask;


4. 첫번째 await 식에 도달할 때까지 메서드는 동기적으로 실행되고 대기 중 작업(awaited task)이 완료될 때까지 메서드는 중단됩니다.

5. 다음 단원의 예제에서처럼 그 동안에는 제어가 메서드 호출자에게 반환됩니다.

6. async 키워드에서 수정하는 메서드에 await 식 또는 문이 없는 경우 해당 메서드가 동기적으로 실행됩니다.

7. async 키워드로 한정된 메서드가 await 식 또는 문을 가지고 있지 않다면 해당 메서드는 동기적으로 실행됩니다.

8. await가 포함되지 않은 모든 비동기 메서드에서는 오류가 발생할 수 있으므로 컴파일러 경고가 나타납니다.

9. 컴파일러 경고(수준 1) CS4014를 참조하십시오.

10. async 키워드는 메서드, 람다 식 또는 무명 메서드를 한정할 때만 키워드로 사용됩니다.

11. 모든 다른 컨텍스트에서는(In all other contexts) 식별자로 해석됩니다.

12. 다음 예제에서는 비동기 이벤트 처리기 StartButton_Click과 비동기 메서드 ExampleMethodAsync 간의 제어 흐름과 구조를 보여 줍니다.

13. 비동기 메서드의 결과는 다운로드한 웹 사이트의 길이입니다.

14. 이 코드는 Visual Studio 2013에서 만든 WPF(Windows Presentation Foundation) 앱 또는 Windows 스토어 앱에 적합합니다(is suitable for).

15. 앱을 설정하는 방법(setting up the apple)은 코드 주석을 참조하십시오.


// You can run this code in Visual Studio 2013 as a WPF app or a Windows Store app.
// You need a button (StartButton) and a textbox (ResultsTextBox).
// Remember to set the names and handler so that you have something like this:
// <Button Content="Button" HorizontalAlignment="Left" Margin="88,77,0,0" VerticalAlignment="Top" Width="75"
//         Click="StartButton_Click" Name="StartButton"/>
// <TextBox HorizontalAlignment="Left" Height="137" Margin="88,140,0,0" TextWrapping="Wrap" 
//          Text="TextBox" VerticalAlignment="Top" Width="310" Name="ResultsTextBox"/>

// To run the code as a WPF app:
//    paste this code into the MainWindow class in MainWindow.xaml.cs,
//    add a reference to System.Net.Http, and
//    add a using directive for System.Net.Http.

// To run the code as a Windows Store app:
//    paste this code into the MainPage class in MainPage.xaml.cs, and
//    add using directives for System.Net.Http and System.Threading.Tasks.

private async void StartButton_Click(object sender, RoutedEventArgs e)
{
    // ExampleMethodAsync returns a Task<int>, which means that the method
    // eventually produces an int result. However, ExampleMethodAsync returns
    // the Task<int> value as soon as it reaches an await.
    ResultsTextBox.Text += "\n";
    try
    {
        int length = await ExampleMethodAsync();
        // Note that you could put "await ExampleMethodAsync()" in the next line where
        // "length" is, but due to when '+=' fetches the value of ResultsTextBox, you
        // would not see the global side effect of ExampleMethodAsync setting the text.
        ResultsTextBox.Text += String.Format("Length: {0}\n", length);
    }
    catch (Exception)
    {
        // Process the exception if one occurs.
    }
}

public async Task<int> ExampleMethodAsync()
{
    var httpClient = new HttpClient();
    int exampleInt = (await httpClient.GetStringAsync("http://msdn.microsoft.com")).Length;
    ResultsTextBox.Text += "Preparing to finish ExampleMethodAsync.\n";
    // After the following return statement, any method that's awaiting
    // ExampleMethodAsync (in this case, StartButton_Click) can get the 
    // integer result.
    return exampleInt;
}
// Output:
// Preparing to finish ExampleMethodAsync.
// Length: 53292


System_CAPS_important중요

작업 및 작업 완료를 기다리는 동안 실행되는 코드에 대한 자세한 내용은 Async 및 Await를 사용한 비동기 프로그래밍(C# 및 Visual Basic)을 참조하십시오. 비슷한 요소를 사용하는 전체 WPF 예제를 보려면 연습: Async 및 Await를 사용하여 웹에 액세스(C# 및 Visual Basic)을 참조하십시오.  개발자 코드 샘플에서 연습 코드를 다운로드할 수 있습니다.  

16. 비동기 메서드의 반환 형식은 Task, Task<TResult> 또는 void일 수 있습니다.

17. 이 메서드는 모든 ref 또는 out 매개 변수를 선언할 수 없지만, 이러한 매개 변수가 있는 메서드를 호출할 수는 있습니다.

18. 메서드의 return 문에서 TResult 형식의 피연산자를 지정할 경우 비동기 메서드의 반환 형식으로 Task<TResult>를 지정합니다.

19. 메서드가 완료 되었을 때 의미 있는 값이 반환되지 않을 경우 Task를 사용합니다.

20. 즉, 이 메서드를 호출하면 Task가 반환되지만 Task가 완료되면 Task를 기다리는 모든 await 식이 void가 됩니다.

21. void 반환 형식은 주로 해당 반환 형식이 필요한 이벤트 처리기를 정의할 때 사용합니다.

22. void 반환 비동기 메서드의 호출자는 기다릴 수 없으므로 메서드가 throw하는 예외를 catch할 수 없습니다.

23. 자세한 내용과 예제를 보려면 비동기 반환 형식을 참조하십시오.





await


1. await 연산자는 비동기 메서드의 작업에 적용되어 대기 중인 작업이 완료될 때까지 메서드의 실행을 일시 중단합니다.

2. 작업은 진행 중인 작업(ongoing work)을 나타냅니다.

3. await가 사용되는 비동기 메서드는 async 키워드로 한정해야 합니다.

4. async 한정자를 사용하여 정의하고 일반적으로 하나 이상의 await 식을 포함하는 이러한 메서드를 비동기 메서드라고 합니다.

System_CAPS_note참고

async 및 await 키워드는 Visual Studio 2012에서 도입되었습니다. 비동기 프로그래밍에 대한 소개는 Async 및 Await를 사용한 비동기 프로그래밍(C# 및 Visual Basic)을 참조하세요.

5. 일반적으로 await 연산자가 적용되는 작업은 작업 기반 비동기 패턴(영문)을 구현하는 메서드를 호출하여 얻은 반환 값입니다.

6. 예를 들어 Task 또는 Task<TResult> 형식의 값이 포함됩니다.

7. 다음 코드에서 HttpClient 메서드 GetByteArrayAsync는 Task<byte[]>, getContentsTask를 반환합니다.

8. 작업은 작업이 완료될 때 실제 바이트 배열을 생성하기 위한 약속입니다.

9. await 연산자는 getContentsTask에 적용되어 getContentsTask가 완료될 때가지 SumPageSizesAsync의 실행을 일시 중단합니다.

10. 동시에(in the meantime) 컨트롤은 SumPageSizesAsync 호출자에게 반환됩니다.

11. getContentsTask가 완료되면 await 식이 바이트 배열로 계산됩니다.


private async Task SumPageSizesAsync()
{
    // To use the HttpClient type in desktop apps, you must include a using directive and add a 
    // reference for the System.Net.Http namespace.
    HttpClient client = new HttpClient();
    // . . .
    Task<byte[]> getContentsTask = client.GetByteArrayAsync(url);
    byte[] urlContents = await getContentsTask;

    // Equivalently, now that you see how it works, you can write the same thing in a single line.
    //byte[] urlContents = await client.GetByteArrayAsync(url);
    // . . .
}


System_CAPS_important중요

전체 예제는 연습: Async 및 Await를 사용하여 웹에 액세스(C# 및 Visual Basic)을 참조하세요. 샘플은 Microsoft 웹 사이트의 개발자 코드 샘플(영문)에서 다운로드할 수 있습니다. 예제는 AsyncWalkthrough_HttpClient 프로젝트에 있습니다.

12. 이전 예제와 같이 await가 Task<TResult>를 반환하는 메서드 호출의 결과에 적용되는 경우 await식의 형식은 TResult입니다.

13. await가 Task를 반환하는 메서드 호출의 결과에 적용되는 경우 await식의 형식은 void입니다.

14. 다음 예제에서 차이점을 보여 줍니다(illustrate).


// Keyword await used with a method that returns a Task<TResult>.
TResult result = await AsyncMethodThatReturnsTaskTResult();

// Keyword await used with a method that returns a Task.
await AsyncMethodThatReturnsTask();


15. await 식은 해당 식이 실행되고 있는 스레드를 차단하지 않습니다.

16. 대신 컴파일러가 대기 중인 작업에서 연속된 작업으로 비동기 메서드의 나머지 부분을 등록(sign up)하도록 합니다.

17. 그런 다음 컨트롤이 비동기 메서드 호출자에게 반환됩니다.

18. 작업이 완료되면 해당 연속 작업이 호출되고 중단된 비동기 메서드의 실행이 다시 시작됩니다.

19. await 식은 바로 바깥쪽의 메서드(an immediately enclosing method), 람다 식 또는 async 한정자로 표시되는 무명 메서드의 본문에서만 발생할 수 있습니다.

20. await라는 용어(the term)는 해당 컨텍스트에서만 키워드 역할을 합니다(serve as).

21. 다른 컨텍스트에서는(Elsewhere) 식별자로 해석됩니다(interprete).

22. 메서드, 람다 식, 무명 메서드 내에서 await 식은 동기 함수의 본문, 쿼리 식, lock 문의 블록 또는 안전하지 않은 컨텍스트에서 발생할 수 없습니다.

23. 대부분의 비동기 메서드는 Task 또는 Task<TResult>를 반환합니다.

24. 반환된 작업의 속성은 작업의 완료 여부, 비동기 메서드가 예외를 발생시켰는지 취소되었는지 여부 및 최종 결과 등 해당 상태(status) 및 기록(history)에 대한 정보를 전달합니다.

25. await 연산자는 해당 속성에 액세스합니다.

26. 예외를 발생시키는 작업 반환 비동기 메서드를 기다릴 경우 await 연산자는 예외를 다시 throw합니다.

27. 취소된 작업 반환 비동기 메서드를 기다릴 경우 await 연산자는 OperationCanceledException을 다시 throw합니다.

28. 오류가 발생한 상태(in a faulted state)의 단일 작업에는 여러 예외가 반영될 수 있습니다

29. 예를 들어 작업은 Task.WhenAll 호출의 결과일 수 있습니다.

30. 이러한 작업을 기다릴 경우 await 작업에서 예외 중 하나만 다시 throw합니다.

31. 그러나 다시 throw되는 예외를 예측할 수 없습니다.

32. 비동기 메서드에서 오류 처리에 대한 예제는 try-catch를 참조하세요.

33. 다음 윈도우 폼 예제는 비동기 메서드 WaitAsynchronouslyAsync에서의 await 사용법을 보여줍니다.

34. 해당 메서드의 동작을 WaitSynchronously의 동작과 대조합니다.

35. await 연산자가 작업에 적용되지 않으면 해당 정의에서 async 한정자를 사용하고 본문에서 Thread.Sleep을 호출하더라도 WaitSynchronously가 동기적으로 실행됩니다.


private async void button1_Click(object sender, EventArgs e) { // 비동기적으로 작동되는 메서드 호출 string result = await WaitAsynchronouslyAsync(); // 동기적으로 작동되는 메서드 호출 //string result = await WaitSynchronously (); // 결과 표시 textBox1.Text += result; } // 다음 메서드는 비동기적으로 실행됩니다. // UI 스레드는 delay 동안 차단되지 않습니다. // Task.Delay가 실행되는 동안 Form1 윈도우는 움직이거나 리사이즈할 수 있습니다. public async Task<string> WaitAsynchronouslyAsync() { await Task.Delay(10000); return "Finished"; } // async 한정자의 사용에도 불구하고 다음 메서드는 동기적으로 실행됩니다. // UI 스레드가 차단되었기 때문에 Thread.Sleep이 실행되는 동안 Form1 윈도우를 이동하거나 리사이즈할 수 없습니다. public async Task<string> WaitSynchronously() { // Add a using directive for System.Threading. Thread.Sleep(10000); return "Finished"; }





decending


1. decending 컨텍스트 키워드는 쿼리 식의 orderby 절에서 사용되어 정렬 순서를 내림차순으로 지정합니다.

2. 다음 예제에서는 orderby 절에서 decending을 사용하는 방법을 보여 줍니다.


IEnumerable<string> sortDescendingQuery =
    from vegetable in vegetables
    orderby vegetable descending
    select vegetable;





dynamic


1. dynamic 형식을 사용하면 컴파일 타임 형식 검사를 무시하는(bypass) 작업을 수행할 수 있습니다.

2. 대신 이러한 작업은 런타임에 확인됩니다(resolve).

3. dynamic 형식은 Office Automation API와 같은 COM API, IronPython 라이브러리와 같은 동적 API 및 HTML DOM(문서 개체 모델)에 대한 액세스를 간소화합니다.

4. 형식 dynamic은 대부분의 환경에서(in most circumstances) 형식 object 같이 동작합니다.

5. 그러나 형식 dynamic의 식이 포함된 작업은 컴파일러에서 형식이 확인되지 않습니다.

6. 컴파일러는 작업에 대한 정보를 함께 패키지하고 해당 정보는 나중에 런타임에서 작업을 평가하는 데 사용됩니다.

7. 프로세스의 일부로 형식 dynamic 변수는 object 형식 변수로 컴파일됩니다.

8. 따라서 형식 dynamic은 런타임이 아닌 컴파일 타임에만 존재합니다.

9. 다음 예제는 형식 dynamic의 변수를 형식 object의 변수와 대조합니다.

10. 컴파일 시간에 각 변수 형식을 확인하려면 WriteLine 문에서 dyn 또는 obj 위에 마우스 포인터를 올려 놓습니다.

11. IntelliSense는 dyn에 대해 동적을, obj에 대해 개체를 보여줍니다.


class Program
{
    static void Main(string[] args)
    {
        dynamic dyn = 1;
        object obj = 1;

        // Rest the mouse pointer over dyn and obj to see their
        // types at compile time.
        System.Console.WriteLine(dyn.GetType());
        System.Console.WriteLine(obj.GetType());
    }
}

12. WriteLine 문은 dyn 및 obj 런타임 형식을 표시합니다.

13. 이 시점에서는 모두 동일한 형식 정수입니다.

14. 다음 출력이 생성됩니다.


System.Int32


System.Int32


15. 컴파일 시간에 dyn 및 obj 사이의 차이를 확인하려면 앞의 에제에서 선언과 WriteLine 문 사이에 다음 두 줄을 추가합니다.


dyn = dyn + 3;
obj = obj + 3;


16. 식 obj + 3에 정수와 객체를 추가혀려고 시도한 경우 컴파일러 오류가 보고됩니다.

17. 그러나 dyn + 3에 대해서는 오류가 보고되지 않습니다.

18. dyn이 포함된 식은 dyn의 형식이 dynamic이기 때문에 컴파일할 때 확인되지 않습니다.

19. dynamic 키워드는 다음과 같은 경우에 직접 또는 생성된 형식의 구성 요소로 나타날 수 있습니다.

20. 선언에서 속성, 필드, 인덱서, 매개 변수, 반환 값, 지역 변수 또는 형식 제약 조건(constraint)의 입력으로 사용합니다.

21. 다음 클래스 정의는 여러 다른 선언에서 dynamic을 사용합니다.


class ExampleClass
{
    // A dynamic field.
    static dynamic field;

    // A dynamic property.
    dynamic prop { get; set; }

    // A dynamic return type and a dynamic parameter type.
    public dynamic exampleMethod(dynamic d)
    {
        // A dynamic local variable.
        dynamic local = "Local variable";
        int two = 2;

        if (d is int)
        {
            return local;
        }
        else
        {
            return two;
        }
    }
}


22. 명시적 형식 변환에서 변환의 대상 형식으로 사용합니다.


static void convertToDynamic()
{
    dynamic d;
    int i = 20;
    d = (dynamic)i;
    Console.WriteLine(d);

    string s = "Example string.";
    d = (dynamic)s;
    Console.WriteLine(d);

    DateTime dt = DateTime.Today;
    d = (dynamic)dt;
    Console.WriteLine(d);

}
// Results:
// 20
// Example string.
// 2/17/2009 9:12:00 AM


23. 모든 컨텍스트에서 형식은 is 연산자 또는 as 연산자의 오른쪽에 있는 것 같은 값 또는 생성된 형식의 일부로 typeof에 대한 인수로 사용됩니다.

24. 예를 들어, dynamic을 다음 식에 사용할 수 있습니다.


int i = 8;
dynamic d;
// With the is operator.
// The dynamic type behaves like object. The following
// expression returns true unless someVar has the value null.
if (someVar is dynamic) { }

// With the as operator.
d = i as dynamic;

// With typeof, as part of a constructed type.
Console.WriteLine(typeof(List<dynamic>));

// The following statement causes a compiler error.
//Console.WriteLine(typeof(dynamic));


25. 다음 예제의 여러 선언에서 dynamic을 사용합니다.

26. Main 메서드는 또한 컴파일 타임 형식 검사를 런타임 형식 검사와 대조합니다.


using System;

namespace DynamicExamples
{
    class Program
    {
        static void Main(string[] args)
        {
            ExampleClass ec = new ExampleClass();
            Console.WriteLine(ec.exampleMethod(10));
            Console.WriteLine(ec.exampleMethod("value"));

            // The following line causes a compiler error because exampleMethod
            // takes only one argument.
            //Console.WriteLine(ec.exampleMethod(10, 4));

            dynamic dynamic_ec = new ExampleClass();
            Console.WriteLine(dynamic_ec.exampleMethod(10));

            // Because dynamic_ec is dynamic, the following call to exampleMethod
            // with two arguments does not produce an error at compile time.
            // However, itdoes cause a run-time error. 
            //Console.WriteLine(dynamic_ec.exampleMethod(10, 4));
        }
    }

    class ExampleClass
    {
        static dynamic field;
        dynamic prop { get; set; }

        public dynamic exampleMethod(dynamic d)
        {
            dynamic local = "Local variable";
            int two = 2;

            if (d is int)
            {
                return local;
            }
            else
            {
                return two;
            }
        }
    }
}
// Results:
// Local variable
// 2
// Local variable


27. 자세한 내용과 예제를 보려면 dynamic 형식 사용을 참조하십시오.





from


1. 쿼리 식은 from 절로 시작해야 합니다.

2. 또한(Additionally) 쿼리 식은 마찬가지로 from 절로 시작하는 하위 쿼리를 포함할 수 있습니다.

3. from 절은 다음을 지정합니다.

    1) 쿼리 또는 하위 쿼리가 실행되는 데이터 소스

    2) 소스 시퀀스의 각 요소를 나타내는 지역 범위 변수(a local range variable)

4. 범위 변수와 데이터 소스는 둘 다 강력한 형식(is strongly typed)입니다.

5. from 절에서 참조되는 데이터 소스는 IEnumerable 또는 IEnumerable<T> 형식이나 IQueryable<T>과 같은 파생 형식이어야 합니다.

6. 다음 예제에서 numbers는 데이터 소스이고 num은 범위 변수입니다.

7. var 키워드가 사용되어도 두 변수는 모두 강력한 형식입니다.


class LowNums
{
    static void Main()
    {   
        // A simple data source.
        int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };

        // Create the query.
        // lowNums is an IEnumerable<int>
        var lowNums = from num in numbers
            where num < 5
            select num;

        // Execute the query.
        foreach (int i in lowNums)
        {
            Console.Write(i + " ");
        }
    }        
}
// Output: 4 1 3 2 0


8. 컴파일러는 데이터 소스가 IEnumerable<T>을 구현할 경우 범위 변수의 형식을 유추합니다.

9. 예를 들어, 소스의 형식이 IEnumerable<Customer>일 경우 범위 변수는 Customer로 유추됩니다(infer).

10. 소스가 ArrayList와 같은 제네릭이 아닌 IEnumerable 형식일 경우에만 형식을 명시적으로 지정하면 됩니다.

11. 자세한 내용은 방법: LINQ를 사용하여 ArrayList 쿼리를 참조하십시오.

12. 위의 예제에서 num은 int 형식으로 유추됩니다.

13. 범위 변수가 강력한 형식이므로 범위 변수에서 메서드를 호출하거나 다른 작업에서 범위 변수를 사용할 수 있습니다.

14. 예를 들어, select num을 작성하는 대신에 select num.ToString()을 작성하여 쿼리 식에서 정수 대신 문자열 시퀀스를 반환하게 할 수 있습니다.

15. 또는 select n + 10을 작성하여 식에서 14, 11, 13, 12, 10 시퀀스를 반환하게 할 수 있습니다.

16. 자세한 내용은 select 절을 참조하십시오.

17. 범위 변수가 소스의 데이터를 실제로 저장하지 않는다는 매우 중요한 차이점을 제외하면 범위 변수는 foreach 문의 반복 변수와 같습니다.

18. 범위 변수는 단순히 쿼리 실행 시에 발생하는 작업을 쿼리에서 설명할 수 있게 하는 구문상의 편리함(a syntactic convenience)을 제공합니다.

19. 자세한 내용은 LINQ 쿼리 소개를 참조하십시오.

20. 경우에 따라 소스 시퀀스의 각 요소 자체가 시퀀스이거나 시퀀스를 포함할 수 있습니다.

21. 예를 들어, 시퀀스의 각 학생 개체에 테스트 점수 목록이 포함된 IEnumerable<Student>가 데이터 소스일 수 있습니다.

22. 각 Student 요소 내에 내부 목록(the inner list)에 액세스하려면 복합 from 절(compound from clauses)을 사용합니다.

23. 이 기술(the technique)은 중첩된 foreach 문을 사용하는 것과 같습니다.

24. where 또는 orderby 절을 둘 중 하나의 from 절에 추가하여 결과를 필터링할 수 있습니다.

25. 다음 예제에서는 테스트 점수를 나타내는 정수의 내부 List를 각각 포함하는 Student 개체의 시퀀스를  보여 줍니다.

26. 내부 목록에 액세스 하려면 복합 from 절을 사용합니다.

27. 필요한 경우 두 개의 from 절 사이에 다른 절을 삽입할 수 있습니다.


class CompoundFrom
{
    // The element type of the data source.
    public class Student
    {
        public string LastName { get; set; }
        public List<int> Scores {get; set;}
    }

    static void Main()
    {

        // Use a collection initializer to create the data source. Note that 
        // each element in the list contains an inner sequence of scores.
        List<Student> students = new List<Student>
        {
           new Student {LastName="Omelchenko", Scores= new List<int> {97, 72, 81, 60}},
           new Student {LastName="O'Donnell", Scores= new List<int> {75, 84, 91, 39}},
           new Student {LastName="Mortensen", Scores= new List<int> {88, 94, 65, 85}},
           new Student {LastName="Garcia", Scores= new List<int> {97, 89, 85, 82}},
           new Student {LastName="Beebe", Scores= new List<int> {35, 72, 91, 70}} 
        };        

        // Use a compound from to access the inner sequence within each element.
        // Note the similarity to a nested foreach statement.
        var scoreQuery = from student in students
                         from score in student.Scores
                            where score > 90
                            select new { Last = student.LastName, score };

        // Execute the queries.
        Console.WriteLine("scoreQuery:");
        // Rest the mouse pointer on scoreQuery in the following line to 
        // see its type. The type is IEnumerable<'a>, where 'a is an 
        // anonymous type defined as new {string Last, int score}. That is,
        // each instance of this anonymous type has two members, a string 
        // (Last) and an int (score).
        foreach (var student in scoreQuery)
        {
            Console.WriteLine("{0} Score: {1}", student.Last, student.score);
        }

        // Keep the console window open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }       
}
/*
scoreQuery:
Omelchenko Score: 97
O'Donnell Score: 91
Mortensen Score: 94
Garcia Score: 97
Beebe Score: 91
*/


28. 복합 from 절은 단일 데이터 소스의 내부 컬렉션에 액세스하는 데 사용됩니다. 그러나 독립 데이터 소스의 추가 쿼리를 생성하는 여러 from 절이 쿼리에 포함될 수도 있습니다.

29. 그러나 독립 데이터 소스의 추가 쿼리(supplemental queries)를 생성하는 여러 from 절이 쿼리에 포함될 수도 있습니다.

30. 이 기술을 사용하면 join 절로 수행할 수 없는 특정 유형의 조인 작업을 수행할 수 있습니다.

31. 다음 예제에서는 두 개의 from 절을 사용하여 두 데이터 소스의 완전한 크로스 조인을 구성하는 방법을 보여 줍니다.


class CompoundFrom2
{
    static void Main()
    {
        char[] upperCase = { 'A', 'B', 'C' };
        char[] lowerCase = { 'x', 'y', 'z' };

        // The type of joinQuery1 is IEnumerable<'a>, where 'a
        // indicates an anonymous type. This anonymous type has two
        // members, upper and lower, both of type char.
        var joinQuery1 =
            from upper in upperCase
            from lower in lowerCase
            select new { upper, lower };

        // The type of joinQuery2 is IEnumerable<'a>, where 'a
        // indicates an anonymous type. This anonymous type has two
        // members, upper and lower, both of type char.
        var joinQuery2 =
            from lower in lowerCase
            where lower != 'x'
            from upper in upperCase
            select new { lower, upper };


        // Execute the queries.
        Console.WriteLine("Cross join:");
        // Rest the mouse pointer on joinQuery1 to verify its type.
        foreach (var pair in joinQuery1)
        {
            Console.WriteLine("{0} is matched to {1}", pair.upper, pair.lower);
        }

        Console.WriteLine("Filtered non-equijoin:");
        // Rest the mouse pointer over joinQuery2 to verify its type.
        foreach (var pair in joinQuery2)
        {
            Console.WriteLine("{0} is matched to {1}", pair.lower, pair.upper);
        }

        // Keep the console window open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}
/* Output:
        Cross join:
        A is matched to x
        A is matched to y
        A is matched to z
        B is matched to x
        B is matched to y
        B is matched to z
        C is matched to x
        C is matched to y
        C is matched to z
        Filtered non-equijoin:
        y is matched to A
        y is matched to B
        y is matched to C
        z is matched to A
        z is matched to B
        z is matched to C
        */


32. 여러 from 절을 사용하는 조인 작업에 대한 자세한 내용은 방법: 사용자 지정 조인 작업 수행을 참조하십시오.





get


1. get 키워드는 속성 값 또는 인덱서 요소를 검색(retrieve)하는 접근자 메서드(an accessor method)를 속성 또는 인덱서에 정의합니다.

2. 자세한 내용은 속성, 자동으로 구현된 속성인덱서를 참조하십시오.

3. 다음은 Secnods라는 속성의 get 접근자 예제입니다.


class TimePeriod
{
    private double _seconds;
    public double Seconds
    {
        get { return _seconds; }
        set { _seconds = value; }
    }
}


4. 다음은 자동으로 구현된 속성의 get 접근자에 대한 예제입니다.


class TimePeriod2
{
    public double Hours { get; set; }
}





global


1. global 컨텍스트 키워드가 :: 연산자 앞에 배치되는 경우 이 키워드는 모든 C# 프로그램의 기본 네임스페이스이며 다른 경우에는 명명되지 않는 전역 네임스페이스를 가리킵니다.

2. 자세한 내용은 법: 전역 네임스페이스 별칭 사용을 참조하십시오.

3. 다음 예제에서는 global 컨텍스트 키워드를 사용하여 클래스 TestApp가 전역 네임스페이스에서 정의되도록 지정하는 방법을 보여 줍니다.


class TestClass : global::TestApp { }





group


1. group 절은 그룹의 키 값과 일치하는 하나 이상의 항목을 포함하는 IGrouping<TKey, TElement> 개체 시퀀스를 반환합니다.

2. 예를 들어 각 문자열의 첫글자에 따라 문자열 시퀀스를 그룹화할 수 있습니다.

3. 이 경우 첫 글자가 키가 되고 키의 형식은 char이며 각 IGrouping<TKey, TElement> 개체의 Key 속성에 저장됩니다.

4. 컴파일러가 키의 형식을 유추(infer)합니다.

5. 다음 예제와 같이 group 절을 사용하여 쿼리 식을 끝낼 수 있습니다.


// Query variable is an IEnumerable<IGrouping<char, Student>>
var studentQuery1 =
    from student in students
    group student by student.Last[0];


6. 각 그룹에서 추가 쿼리 작업(additional query operations)을 수행(perform)하려면 into 컨텍스트 키워드를 사용하여 임시 식별자(a temporary identifier)를 지정할 수 있습니다.

7. into를 사용하는 경우 다음 발췌(excerpt) 내용과 같이 쿼리를 계속하여 select 문이나 다른 group 절로 끝내야 합니다.


// Group students by the first letter of their last name
// Query variable is an IEnumerable<IGrouping<char, Student>>
var studentQuery2 =
    from student in students
    group student by student.Last[0] into g
    orderby g.Key
    select g;


8. into를 사용하거나 사용하지 않고 group을 사용하는 방법을 보여 주는 보다 완전한 예제는 이 항목의 예제 단원을 참조하십시오.

9. group 쿼리의 의해 생성된 IGrouping<TKey, TElement> 개체는 기본적으로(essentially) 목록의 목록이므로 foreach 루프를 사용하여 각 그룹의 항목에 액세스해야 합니다.

10. 바깥쪽 루프(the outer loop)는 그룹 키를 반복하고 안쪽 루프는 그룹 자체의 각 항목을 반복합니다.

11. 그룹에 키(key)는 포함될 수 있지만 요소(elements)는 포함될 수 없습니다.

12. 이전 코드 예제에서 쿼리를 실행하는 foreach 루프는 다음과 같습니다.


// Iterate group items with a nested foreach. This IGrouping encapsulates
// a sequence of Student objects, and a Key of type char.
// For convenience, var can also be used in the foreach statement.
foreach (IGrouping<char, Student> studentGroup in studentQuery2)
{
     Console.WriteLine(studentGroup.Key);
     // Explicit type for student could also be used here.
     foreach (var student in studentGroup)
     {
         Console.WriteLine("   {0}, {1}", student.Last, student.First);
     }
 }


13. 그룹 키는 문자열, 기본 제공 숫자 형식 또는 사용자 정의 명명된 형식이나 익명 형식과 같은 임의의 형식일 수 있습니다.

14. 앞의 코드 예제에서는 char를 사용했습니다.

15. 전체 성(last name) 등의 문자열 키를 대신 지정할 수도 있습니다.


// Same as previous example except we use the entire last name as a key.
// Query variable is an IEnumerable<IGrouping<string, Student>>
 var studentQuery3 =
     from student in students
     group student by student.Last;


16. 다음 예제에서는 키를 부울 값을 사용하여 결과를 두 개의 그룹으로 나누는 방법을 보여 줍니다.

17. group 절의 하위 식(sub-expression)에서 값이 생성됩니다.


class GroupSample1
{
    // The element type of the data source.
    public class Student
    {
        public string First { get; set; }
        public string Last { get; set; }
        public int ID { get; set; }
        public List<int> Scores;
    }

    public static List<Student> GetStudents()
    {
        // Use a collection initializer to create the data source. Note that each element
        //  in the list contains an inner sequence of scores.
        List<Student> students = new List<Student>
        {
           new Student {First="Svetlana", Last="Omelchenko", ID=111, Scores= new List<int> {97, 72, 81, 60}},
           new Student {First="Claire", Last="O'Donnell", ID=112, Scores= new List<int> {75, 84, 91, 39}},
           new Student {First="Sven", Last="Mortensen", ID=113, Scores= new List<int> {99, 89, 91, 95}},
           new Student {First="Cesar", Last="Garcia", ID=114, Scores= new List<int> {72, 81, 65, 84}},
           new Student {First="Debra", Last="Garcia", ID=115, Scores= new List<int> {97, 89, 85, 82}} 
        };

        return students;

    }

    static void Main()
    {
        // Obtain the data source.
        List<Student> students = GetStudents();

        // Group by true or false.
        // Query variable is an IEnumerable<IGrouping<bool, Student>>
        var booleanGroupQuery =
            from student in students
            group student by student.Scores.Average() >= 80; //pass or fail!

        // Execute the query and access items in each group
        foreach (var studentGroup in booleanGroupQuery)
        {
            Console.WriteLine(studentGroup.Key == true ? "High averages" : "Low averages");
            foreach (var student in studentGroup)
            {
                Console.WriteLine("   {0}, {1}:{2}", student.Last, student.First, student.Scores.Average());
            }
        }

        // Keep the console window open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}
/* Output:
  Low averages
   Omelchenko, Svetlana:77.5
   O'Donnell, Claire:72.25
   Garcia, Cesar:75.5
  High averages
   Mortensen, Sven:93.5
   Garcia, Debra:88.25
*/


18. 다음 예제에서는 식을 사용하여 백분위수 범위(a percentile range)를 나타내는 숫자 그룹 키를 만듭니다.

19. group 절에서 메서드를 두 번 호출할 필요가 없도록 메서드 호출 결과를 저장할 편리한 위치로 let을 사용합니다.

20. 또한 "0으로 나누기(divide by zero)" 예외를 방지하기 위해 이 코드는 group 절에서 학생의 평균이 0이 아닌지 확인합니다.

21. 쿼리 식에서 메서드를 안전하게 사용하는 방법에 대한 자세한 내용은 방법: 쿼리 식의 예외 처리를 참조하십시오.


class GroupSample2
{
    // The element type of the data source.
    public class Student
    {
        public string First { get; set; }
        public string Last { get; set; }
        public int ID { get; set; }
        public List<int> Scores;
    }

    public static List<Student> GetStudents()
    {
        // Use a collection initializer to create the data source. Note that each element
        //  in the list contains an inner sequence of scores.
        List<Student> students = new List<Student>
        {
           new Student {First="Svetlana", Last="Omelchenko", ID=111, Scores= new List<int> {97, 72, 81, 60}},
           new Student {First="Claire", Last="O'Donnell", ID=112, Scores= new List<int> {75, 84, 91, 39}},
           new Student {First="Sven", Last="Mortensen", ID=113, Scores= new List<int> {99, 89, 91, 95}},
           new Student {First="Cesar", Last="Garcia", ID=114, Scores= new List<int> {72, 81, 65, 84}},
           new Student {First="Debra", Last="Garcia", ID=115, Scores= new List<int> {97, 89, 85, 82}} 
        };

        return students;

    }

    // This method groups students into percentile ranges based on their
    // grade average. The Average method returns a double, so to produce a whole
    // number it is necessary to cast to int before dividing by 10. 
    static void Main()
    {
        // Obtain the data source.
        List<Student> students = GetStudents();

        // Write the query.
        var studentQuery =
            from student in students
            let avg = (int)student.Scores.Average()
            group student by (avg == 0 ? 0 : avg / 10) into g
            orderby g.Key
            select g;            

        // Execute the query.
        foreach (var studentGroup in studentQuery)
        {
            int temp = studentGroup.Key * 10;
            Console.WriteLine("Students with an average between {0} and {1}", temp, temp + 10);
            foreach (var student in studentGroup)
            {
                Console.WriteLine("   {0}, {1}:{2}", student.Last, student.First, student.Scores.Average());
            }
        }

        // Keep the console window open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}
/* Output:
     Students with an average between 70 and 80
       Omelchenko, Svetlana:77.5
       O'Donnell, Claire:72.25
       Garcia, Cesar:75.5
     Students with an average between 80 and 90
       Garcia, Debra:88.25
     Students with an average between 90 and 100
       Mortensen, Sven:93.5
 */


22. 둘 이상의 키에 따라 요소를 그룹화하려는 경우 복합(composite) 키를 사용합니다.

23. 키 요소를 담기 위해서 익명 형식이나 명명된 형식으로 복합 키를 만듭니다.

24. 예제에서는 Person 클래스가 surname 및 city라는 멤버로 선언되었다고 가정합니다(assume).

25. group 클래스는 성과 구/군/시가 같은 각 개인 집합에 대해 별도의 그룹이 만들어지게 합니다.


group person by new {name = person.surname, city = person.city};


26. 쿼리 변수를 다른 메서드로 전달해야 하는 경우 명명된 형식을 사용합니다.

27. 키에 대해 자동 구현된 속성을 사용하여 특수 클래스를 만든 다음 EqualsGetHashCode 메서드를 재정의합니다.

28. 이러한 메서드를 반드시 재정의할 필요가 없는 구조체를 사용할 수도 있습니다.

29. 자세한 내용은 방법: 자동으로 구현된 속성을 사용하여 간단한 클래스 구현How to: Query for Duplicate Files in a Directory Tree (LINQ)을 참조하십시오.

30. 두 번째 항목에는 복합 키에 명명된 형식을 사용하는 방법을 보여 주는 코드 예제가 있습니다.

31. 다음 예제에서는 그룹에 적용되는 추가 쿼리 논리가 없을 때 소스 데이터를 그룹으로 정렬하기 위한 표준 패턴(the standard pattern)을 보여 줍니다.

32. 이를 비연속 그룹화(a grouping without a continuation)라고 합니다.

33. 문자열 배열의 요소는 첫 글자에 따라 그룹화됩니다.

34. 쿼리 결과는 그룹의 각 항목을 포함하는 IEnumerable<T> 컬렉션 및 char 형식의 public Key 속성을 포함하는 IGrouping<TKey, TElement> 형식입니다.

35. group 절의 결과는 시퀀스의 시퀀스입니다.

36. 따라서 반환된 각 그룹 내의 개별 요소에 액세스하려면 다음 예제와 같이 그룹 키를 반복하는 루프 내부의 중첩 foreach 루프를 사용합니다.


class GroupExample1
{
    static void Main()
    {
        // Create a data source.
        string[] words = { "blueberry", "chimpanzee", "abacus", "banana", "apple", "cheese" };

        // Create the query.
        var wordGroups =
            from w in words
            group w by w[0];

        // Execute the query.
        foreach (var wordGroup in wordGroups)
        {
            Console.WriteLine("Words that start with the letter '{0}':", wordGroup.Key);
            foreach (var word in wordGroup)
            {
                Console.WriteLine(word);
            }
        }

        // Keep the console window open in debug mode
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }        
}
/* Output:
      Words that start with the letter 'b':
        blueberry
        banana
      Words that start with the letter 'c':
        chimpanzee
        cheese
      Words that start with the letter 'a':
        abacus
        apple
     */


37. 이 예제에서는 연속에 into를 사용하여 그룹을 만든 후 그룹에서 추가 논리(logic)를 수행하는 방법을 보여줍니다.

38. 자세한 내용은 into를 참조하십시오.

39. 다음 예제에서는 각 그룹을 쿼리하여 키 값이 모음(vowel)인 그룹만 선택합니다.


class GroupClauseExample2
{
    static void Main()
    {
        // Create the data source.
        string[] words2 = { "blueberry", "chimpanzee", "abacus", "banana", "apple", "cheese", "elephant", "umbrella", "anteater" };

        // Create the query.
        var wordGroups2 =
            from w in words2
            group w by w[0] into grps
            where (grps.Key == 'a' || grps.Key == 'e' || grps.Key == 'i'
                   || grps.Key == 'o' || grps.Key == 'u')
            select grps;

        // Execute the query.
        foreach (var wordGroup in wordGroups2)
        {
            Console.WriteLine("Groups that start with a vowel: {0}", wordGroup.Key);
            foreach (var word in wordGroup)
            {
                Console.WriteLine("   {0}", word);
            }
        }

        // Keep the console window open in debug mode
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}
/* Output:
    Groups that start with a vowel: a
        abacus
        apple
        anteater
    Groups that start with a vowel: e
        elephant
    Groups that start with a vowel: u
        umbrella
*/    


40. 컴파일 타임에 group 절은 GroupBy<TSource, TKey> 메서드에 대한 호출로 변환(translated into)됩니다.





into


1. 컨텍스트 키워드 into는 group, join, select 절의 결과를 새 식별자에 저장하는 임시 식별자(a temporary identifier)를 만드는 데 사용할 수 있습니다.

2. 이 식별자 자체는 추가 쿼리 명령에 대한 생성기(a generator)가 될 수 있습니다.

3. group 또는 select 절에서 사용되는 경우 새 식별자의 사용을 연속(a continuation)이라고도 합니다.

4. 다음 예제에서는 IGrouping의 유추된 형식(an inferred type)을 포함하는 임시 식별자 fruitGroup을 활성화하도록 into 키워드를 사용하는 방법을 보여 줍니다.

5. 식별자를 사용하여 각 그룹에서 Count 메서드를 호출하고 두 개 이상의 단어를 포함하는 해당 그룹만 선택할 수 있습니다.


class IntoSample1
{
    static void Main()
    {

        // Create a data source.
        string[] words = { "apples", "blueberries", "oranges", "bananas", "apricots"};

        // Create the query.
        var wordGroups1 =
            from w in words
            group w by w[0] into fruitGroup
            where fruitGroup.Count() >= 2
            select new { FirstLetter = fruitGroup.Key, Words = fruitGroup.Count() };

        // Execute the query. Note that we only iterate over the groups, 
        // not the items in each group
        foreach (var item in wordGroups1)
        {
            Console.WriteLine(" {0} has {1} elements.", item.FirstLetter, item.Words);
        }

        // Keep the console window open in debug mode
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}
/* Output:
   a has 2 elements.
   b has 2 elements.
*/


6. 각 그룹에 대해 추가 쿼리 작업을 수행하려는 경우에만 group 절에 into 를 사용해야 합니다.

7. 자세한 내용은 group 절을 참조하십시오.

8. join 절에서 into를 사용하는 방법에 대한 예제는 join 절을 참조하십시오.





join


1. join 절은 개체 모델에서 직접 관계(direct relationship)가 없는 여러 소스 시퀀스의 요소를 연결(associate)하는 데 유용합니다.

2. 유일한 요구 사항(requirement)은 각 소스의 요소가 같은지(equality) 비교할 수 있는 일부 값을 공유해야 한다는 것입니다.

3. 예를 들어 식품 유통업체(a food distributor)에는 특정 제품(a certain product)의 공급자 목록(a list of suppliers)과 구매자 목록(a list of buyers)이 있을 수 있습니다.

4. 예를 들어 해당 제품의 공급자와 구매자가 모두 동일한 특정 지역에 있는 경우 join 절을 사용하여 이러한 공급자와 구매자의 목록을 만들 수 있습니다.

5. join 절은 두 개의 소스 시퀀스를 입력으로 사용합니다.

6. 각 시퀀스의 요소는 다른 시퀀스의 해당 속성(a corresponding property)과 비교할 수 있는 속성이거나 이러한 속성을 포함해야 합니다.

7. join 절은 특별한 equals 키워드를 사용하여 지정된 키가 같은지 비교합니다.

8. join 절에서 수행하는 모든 join은 동등 조인(equijoins)입니다.

9. join 절의 출력 모양은 수행하는 특정 조인 형식에 따라 달라집니다.

10. 가장 일반적인(common) 세 가지 조인 형식은 다음과 같습니다.

    1) 내부 조인

    2) 그룹 조인

    3) 왼쪽 우선 외부 조인

<내부 조인>

11. 다음 예제에서는 단순한 내부 동등 조인(a simple inner equijoin)을 보여 줍니다.

12. 이 쿼리는 "제품 이름/범주"쌍의 기본(flat) 시퀀스를 생성합니다.

13. 동일한 범주 문자열(the same category string)이 여러 요소에 나타납니다

14. categories의 요소에 일치하는 products가 없을 경우(have no matching products) 해당 범주는 결과에 표시되지 않습니다.


var innerJoinQuery =
    from category in categories
    join prod in products on category.ID equals prod.CategoryID
    select new { ProductName = prod.Name, Category = category.Name }; //produces flat sequence


15. 자세한 내용은 방법: 내부 조인 수행을 참조하십시오.

<그룹 조인>

16. into 식이 있는 join 절을 그룹 조인이라고 합니다.


var innerGroupJoinQuery =
    from category in categories
    join prod in products on category.ID equals prod.CategoryID into prodGroup
    select new { CategoryName = category.Name, Products = prodGroup };

 

17. 그룹 조인은 왼쪽 소스 시퀀스의 요소를 오른쪽 소스 시퀀스에 있는 하나 이상의 일치하는 요소와 연결하는 계층적 결과(a hierarchical result)를 생성합니다.

18. 그룹 조인은 동등한 관계형 용어가 없으며 기본적으로 개체 배열의 시퀀스입니다.

19. 왼쪽 소스의 요소와 일치하는 오른족 소스 시퀀스의 요소가 없을 경우 join 절은 해당 항목에 대해 빈 배열을 생성합니다.

20. 따라서 그룹 조인은 결과 시퀀스가 그룹으로 구성(organize)된다는 점을 제외하고 기본적으로(basically) 내부동등 조인입니다.

21. 단순히 그룹 조인의 결과를 선택하면 항목에 액세스할 수 있지만 항목이 일치하는 키를 식별할 수는 없습니다.

22. 따라서 앞의 예제와 같이 그룹 조인의 결과를 키 이름도 있는 새 형식으로 선택하는 것이 더 유용합니다.

23. 물론 그룹 조인의 결과를 다른 하위 쿼리(another subquery)의 생성기르 사용할 수도 있습니다.


var innerGroupJoinQuery2 =
    from category in categories
    join prod in products on category.ID equals prod.CategoryID into prodGroup
    from prod2 in prodGroup
    where prod2.UnitPrice > 2.50M
    select prod2;


24. 자세한 내용은 방법: 그룹화 조인 수행을 찹조하십시오.

<왼쪽 우선 외부 조인>

25. 왼쪽 우선 외부 조인(a left outer join)에서는 오른쪽 시퀀스에 일치하는 요소가 없는 경우에는 왼쪽 소스 시퀀스의 모든 요소가 반환됩니다.

26. LINQ에서 왼쪽 우선 외부 조인을 수행하려면 DefaultIfEmpty 메서드를 그룹 조인과 함께 사용하여 왼쪽 요소에 일치 항목이 없을 경우 생성할 기본 오른쪽 요소를 지정합니다.

27. null을 참조 형식의 기본값으로 사용하거나 사용자 정의 기본 형식을 지정할 수 있습니다.

28. 다음 예제에서는 사용자 정의 기본 형식이 표시됩니다.


var leftOuterJoinQuery =
    from category in categories
    join prod in products on category.ID equals prod.CategoryID into prodGroup
    from item in prodGroup.DefaultIfEmpty(new Product { Name = String.Empty, CategoryID = 0 })
    select new { CatName = category.Name, ProdName = item.Name };


29. 자세한 내용은 방법: 왼쪽 우선 외부 조인 수행을 참조하십시오.

<같음 연산자>

30. join 절은 동등 조인을 수행합니다.

31. 즉(In other words), 일치 항목만 기준으로 두 키가 같은지 비교할 수 있습니다.

32. "보다 큼(greater than)", 또는 "같지 않음(not equals)"과 같은 다른 비교 형식은 지원되지 않습니다.

33. 모든 조인이 동등 조인임을 확인하기 위해(To make clear that) join절은 == 연산자 대신 equals 키워드를 사용합니다.

34. equals 키워드는 join 절에서만 사용할 수 있으며 == 연산자와 중요한 한 가지 차이점이 있습니다.

35. equals를 사용하는 경우 왼쪽 키는 외부 소스 시퀀스를 사용하고(consume) 오른쪽 키는 내부 소스를 사용합니다.

36. 외부 소스는 equals의 왼쪽 범위에만 있고 내부 소스 시퀀스는 오른쪽 범위에만 있습니다.

<비동등 조인>

37. 여러 개의 from 절을 사용하여 새 시퀀스를 개별적으로(independently) 쿼리에 적용하면 비동등 조인(non-equijoins), 교차 조인(cross joins) 및 기타 사용자 지정 조인(other custom join) 작업을 수행할 수 있습니다.

38. 자세한 내용은 방법: 사용자지정 조인 작업 수행을 참조하십시오.

<개체 컬렉션 및 관계형 테이블의 조인>

39. LINQ 쿼리 식에서는 조인 작업이 개체 컬력션에서 수행됩니다.

40. 개체 컬렉션은 두 개의 관계형 테이블과 정확히 동일한 방식으로 "조인"할 수 없습니다.

41. LINQ에서 명시적(explicit) join 절은 두 개의 소스 시퀀스가 어떤 관계로도 연결(tie)되지 않은 경우에만 필요합니다.

42. LINQ to SQL을 사용하는 경우 외래 키 테이블은 개체 모델에 기본 테이블(the primary table)의 속성으로 표현됩니다.

43. 예를 들어 Northwind 데이터베이스의 Customer 테이블은 Orders 테이블과 외래 키 관계가 있습니다.

44. 테이블을 개체 모델에 매핑하면 Customer 클래스에 해당 Customer와 연결된 Orders 컬렉션을 포함하는 Orders 속성이 있습니다.

45. 실제로(In effect) 조인이 이미 수정되었습니다.

46. LINQ to SQL 컨텍스트에서 관계형 테이블을 쿼리하는 방법에 대한 자세한 내용은 방법: 데이터베이스 관계 매을 참조하십시오.

<복합 키>

47. 복합 키를 사용하여 여러 값이같은지 테스트할 수 있습니다.

48. 자세한 내용은 방법: 복합 키를 사용하여 조인을 참조하십시오.

49. 복합 키는 group 절에서도 사용할 수 있습니다.

<예제>

50. 다음 예제에서는 일치하는 동일한 키를 사용하여 동일한 데이터 소스에서 수행한 내부 조인, 그룹 조인 및  왼쪽 우선 외부 조인의 결과를 비교합니다.

51. 콘솔 표시의 결과를 명확(clarify)하게 지정하기 위해 이러한 예제에 일부 다른 코드(some extra code)가 추가됩니다.


class JoinDemonstration
{
    #region Data

    class Product
    {
        public string Name { get; set; }
        public int CategoryID { get; set; }
    }

    class Category
    {
        public string Name { get; set; }
        public int ID { get; set; }
    }

    // Specify the first data source.
    List<Category> categories = new List<Category>()
    { 
        new Category(){Name="Beverages", ID=001},
        new Category(){ Name="Condiments", ID=002},
        new Category(){ Name="Vegetables", ID=003},
        new Category() { Name="Grains", ID=004},
        new Category() { Name="Fruit", ID=005}            
    };

    // Specify the second data source.
    List<Product> products = new List<Product>()
   {
      new Product{Name="Cola",  CategoryID=001},
      new Product{Name="Tea",  CategoryID=001},
      new Product{Name="Mustard", CategoryID=002},
      new Product{Name="Pickles", CategoryID=002},
      new Product{Name="Carrots", CategoryID=003},
      new Product{Name="Bok Choy", CategoryID=003},
      new Product{Name="Peaches", CategoryID=005},
      new Product{Name="Melons", CategoryID=005},
    };
    #endregion


    static void Main(string[] args)
    {
        JoinDemonstration app = new JoinDemonstration();

        app.InnerJoin();
        app.GroupJoin();
        app.GroupInnerJoin();
        app.GroupJoin3();
        app.LeftOuterJoin();
        app.LeftOuterJoin2();

        // Keep the console window open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }

    void InnerJoin()
    {
        // Create the query that selects 
        // a property from each element.
        var innerJoinQuery =
           from category in categories
           join prod in products on category.ID equals prod.CategoryID
           select new { Category = category.ID, Product = prod.Name };

        Console.WriteLine("InnerJoin:");
        // Execute the query. Access results 
        // with a simple foreach statement.
        foreach (var item in innerJoinQuery)
        {
            Console.WriteLine("{0,-10}{1}", item.Product, item.Category);
        }
        Console.WriteLine("InnerJoin: {0} items in 1 group.", innerJoinQuery.Count());
        Console.WriteLine(System.Environment.NewLine);

    }

    void GroupJoin()
    {
        // This is a demonstration query to show the output
        // of a "raw" group join. A more typical group join
        // is shown in the GroupInnerJoin method.
        var groupJoinQuery =
           from category in categories
           join prod in products on category.ID equals prod.CategoryID into prodGroup
           select prodGroup;

        // Store the count of total items (for demonstration only).
        int totalItems = 0;

        Console.WriteLine("Simple GroupJoin:");

        // A nested foreach statement is required to access group items.
        foreach (var prodGrouping in groupJoinQuery)
        {
            Console.WriteLine("Group:");
            foreach (var item in prodGrouping)
            {
                totalItems++;
                Console.WriteLine("   {0,-10}{1}", item.Name, item.CategoryID);
            }
        }
        Console.WriteLine("Unshaped GroupJoin: {0} items in {1} unnamed groups", totalItems, groupJoinQuery.Count());
        Console.WriteLine(System.Environment.NewLine);
    }

    void GroupInnerJoin()
    {
        var groupJoinQuery2 =
            from category in categories
            orderby category.ID
            join prod in products on category.ID equals prod.CategoryID into prodGroup
            select new
            {
                Category = category.Name,
                Products = from prod2 in prodGroup
                           orderby prod2.Name
                           select prod2
            };

        //Console.WriteLine("GroupInnerJoin:");
        int totalItems = 0;

        Console.WriteLine("GroupInnerJoin:");
        foreach (var productGroup in groupJoinQuery2)
        {
            Console.WriteLine(productGroup.Category);
            foreach (var prodItem in productGroup.Products)
            {
                totalItems++;
                Console.WriteLine("  {0,-10} {1}", prodItem.Name, prodItem.CategoryID);
            }
        }
        Console.WriteLine("GroupInnerJoin: {0} items in {1} named groups", totalItems, groupJoinQuery2.Count());
        Console.WriteLine(System.Environment.NewLine);
    }

    void GroupJoin3()
    {

        var groupJoinQuery3 =
            from category in categories
            join product in products on category.ID equals product.CategoryID into prodGroup
            from prod in prodGroup
            orderby prod.CategoryID
            select new { Category = prod.CategoryID, ProductName = prod.Name };

        //Console.WriteLine("GroupInnerJoin:");
        int totalItems = 0;

        Console.WriteLine("GroupJoin3:");
        foreach (var item in groupJoinQuery3)
        {
            totalItems++;
            Console.WriteLine("   {0}:{1}", item.ProductName, item.Category);
        }

        Console.WriteLine("GroupJoin3: {0} items in 1 group", totalItems, groupJoinQuery3.Count());
        Console.WriteLine(System.Environment.NewLine);
    }

    void LeftOuterJoin()
    {
        // Create the query.
        var leftOuterQuery =
           from category in categories
           join prod in products on category.ID equals prod.CategoryID into prodGroup
           select prodGroup.DefaultIfEmpty(new Product() { Name = "Nothing!", CategoryID = category.ID });

        // Store the count of total items (for demonstration only).
        int totalItems = 0;

        Console.WriteLine("Left Outer Join:");

        // A nested foreach statement  is required to access group items
        foreach (var prodGrouping in leftOuterQuery)
        {
            Console.WriteLine("Group:", prodGrouping.Count());
            foreach (var item in prodGrouping)
            {
                totalItems++;
                Console.WriteLine("  {0,-10}{1}", item.Name, item.CategoryID);
            }
        }
        Console.WriteLine("LeftOuterJoin: {0} items in {1} groups", totalItems, leftOuterQuery.Count());
        Console.WriteLine(System.Environment.NewLine);
    }

    void LeftOuterJoin2()
    {
        // Create the query.
        var leftOuterQuery2 =
           from category in categories
           join prod in products on category.ID equals prod.CategoryID into prodGroup
           from item in prodGroup.DefaultIfEmpty()
           select new { Name = item == null ? "Nothing!" : item.Name, CategoryID = category.ID };

        Console.WriteLine("LeftOuterJoin2: {0} items in 1 group", leftOuterQuery2.Count());
        // Store the count of total items
        int totalItems = 0;

        Console.WriteLine("Left Outer Join 2:");

        // Groups have been flattened.
        foreach (var item in leftOuterQuery2)
        {
            totalItems++;
            Console.WriteLine("{0,-10}{1}", item.Name, item.CategoryID);
        }
        Console.WriteLine("LeftOuterJoin2: {0} items in 1 group", totalItems);
    }
}
/*Output:

InnerJoin:
Cola      1
Tea       1
Mustard   2
Pickles   2
Carrots   3
Bok Choy  3
Peaches   5
Melons    5
InnerJoin: 8 items in 1 group.


Unshaped GroupJoin:
Group:
    Cola      1
    Tea       1
Group:
    Mustard   2
    Pickles   2
Group:
    Carrots   3
    Bok Choy  3
Group:
Group:
    Peaches   5
    Melons    5
Unshaped GroupJoin: 8 items in 5 unnamed groups


GroupInnerJoin:
Beverages
    Cola       1
    Tea        1
Condiments
    Mustard    2
    Pickles    2
Vegetables
    Bok Choy   3
    Carrots    3
Grains
Fruit
    Melons     5
    Peaches    5
GroupInnerJoin: 8 items in 5 named groups


GroupJoin3:
    Cola:1
    Tea:1
    Mustard:2
    Pickles:2
    Carrots:3
    Bok Choy:3
    Peaches:5
    Melons:5
GroupJoin3: 8 items in 1 group


Left Outer Join:
Group:
    Cola      1
    Tea       1
Group:
    Mustard   2
    Pickles   2
Group:
    Carrots   3
    Bok Choy  3
Group:
    Nothing!  4
Group:
    Peaches   5
    Melons    5
LeftOuterJoin: 9 items in 5 groups


LeftOuterJoin2: 9 items in 1 group
Left Outer Join 2:
Cola      1
Tea       1
Mustard   2
Pickles   2
Carrots   3
Bok Choy  3
Nothing!  4
Peaches   5
Melons    5
LeftOuterJoin2: 9 items in 1 group
Press any key to exit.
*/


52. 뒤에 into가 없는 join 절은 Join<TOuter, TInner, TKey, TResult> 메서드 호출로 변환됩니다.

53. 뒤에 into가 있는 join 절은 GroupJoin<TOuter, TInner, TKey, TResult> 메서드 호출로 변환됩니다.





let


1. 쿼리 식에서는 후속 절(subsequent clauses)에서 쿼리 식을 사용하기 위해 부분식(sub-expression)의 결과를 저장하는 것이 좋습니다.

2. let 키워드를 사용하여 작업을 할 수 있는데 이 키워드는 새로운 범위 변수를 만들고 제공된 식의 결과로 범위 변수를 초기화합니다.

3. 값으로 초기화하고 나면 범위 변수는 다른 값을 저장하는 데 사용될 수 없습니다.

4. 그러나 범위 변수가 쿼리 가능한 형식(a queryable type)을 사용할 경우에는 쿼리할 수 있습니다.

5. 다음 예제에서는 let이 두 가지 방법으로 사용되고 있습니다.

    1) 쿼리될 수 있는 열거 가능한 형식(enumerable type)을 만들기.

    2) 범위 변수 word에서 ToLower를 한번만 호출하기. let을 사용하지 않는다면 where 절의 각 조건자(each predicate)에서 ToLower를 호출해야 합니다.


class LetSample1
{
    static void Main()
    {
        string[] strings = 
        {
            "A penny saved is a penny earned.",
            "The early bird catches the worm.",
            "The pen is mightier than the sword." 
        };

        // Split the sentence into an array of words
        // and select those whose first letter is a vowel.
        var earlyBirdQuery =
            from sentence in strings
            let words = sentence.Split(' ')
            from word in words
            let w = word.ToLower()
            where w[0] == 'a' || w[0] == 'e'
                || w[0] == 'i' || w[0] == 'o'
                || w[0] == 'u'
            select word;

        // Execute the query.
        foreach (var v in earlyBirdQuery)
        {
            Console.WriteLine("\"{0}\" starts with a vowel", v);
        }

        // Keep the console window open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}
/* Output:
    "A" starts with a vowel
    "is" starts with a vowel
    "a" starts with a vowel
    "earned." starts with a vowel
    "early" starts with a vowel
    "is" starts with a vowel
*/





orderby


1. 커리 식에서 orderby 절은 반환된 시퀀스 또는 서브시퀀스 (그룹)을 오름차순이나 내림차순으로(in either ascendig or descending order) 정렬되도록 합니다.

2. 둘 이상의 보조 정렬 작업(one or more secondary sort operations)을 수행하기 위해 여러 개의 키(Multiple keys)를 지정할 수 있습니다.

3. 요소의 형식에 대한 기본 비교자(default comparer)를 사용하여 정렬 작업(The sorting)을 수행합니다.

4. 기본 정렬 순서(the default sort order)는 오름차순입니다.

5. 사용자 지정 비교자(a custom comparer)를 지정할 수도 있습니다.

6. 자세한 내용은 Sorting Data를 참조하십시오.

7. 다음 예제에서는 첫 번째 쿼리는 A부터 시작하는 사전순(in alphabetical order)으로 정렬하고 두 번째 쿼리에서는 동일한 단어를 내림차순(in descending order)으로 정렬합니다.

8. ascending 키워드는 기본정렬 값이므로 생략(omit)할 수 있습니다.


class OrderbySample1 { static void Main() { // Create a delicious data source. string[] fruits = { "cherry", "apple", "blueberry" }; // Query for ascending sort. IEnumerable<string> sortAscendingQuery = from fruit in fruits orderby fruit //"ascending" is default select fruit; // Query for descending sort. IEnumerable<string> sortDescendingQuery = from w in fruits orderby w descending select w; // Execute the query. Console.WriteLine("Ascending:"); foreach (string s in sortAscendingQuery) { Console.WriteLine(s); } // Execute the query. Console.WriteLine(Environment.NewLine + "Descending:"); foreach (string s in sortDescendingQuery) { Console.WriteLine(s); } // Keep the console window open in debug mode. Console.WriteLine("Press any key to exit."); Console.ReadKey(); } } /* Output: Ascending: apple blueberry cherry Descending: cherry blueberry apple */


9. 다음 예제에서는 학생의 성을 기준으로 기본 정렬(a primary sort)을 수행한 다음 이름 순으로 두 번째 정렬(a secondary sort)을 수행합니다.


class OrderbySample2
{
    // The element type of the data source.
    public class Student
    {
        public string First { get; set; }
        public string Last { get; set; }
        public int ID { get; set; }
    }

    public static List<Student> GetStudents()
    {
        // Use a collection initializer to create the data source. Note that each element
        //  in the list contains an inner sequence of scores.
        List<Student> students = new List<Student>
        {
           new Student {First="Svetlana", Last="Omelchenko", ID=111},
           new Student {First="Claire", Last="O'Donnell", ID=112},
           new Student {First="Sven", Last="Mortensen", ID=113},
           new Student {First="Cesar", Last="Garcia", ID=114},
           new Student {First="Debra", Last="Garcia", ID=115} 
        };

        return students;
    }
    static void Main(string[] args)
    {
        // Create the data source.
        List<Student> students = GetStudents();

        // Create the query.
        IEnumerable<Student> sortedStudents =
            from student in students
            orderby student.Last ascending, student.First ascending
            select student;

        // Execute the query.
        Console.WriteLine("sortedStudents:");
        foreach (Student student in sortedStudents)
            Console.WriteLine(student.Last + " " + student.First);           

        // Now create groups and sort the groups. The query first sorts the names
        // of all students so that they will be in alphabetical order after they are
        // grouped. The second orderby sorts the group keys in alpha order.            
        var sortedGroups =
            from student in students
            orderby student.Last, student.First
            group student by student.Last[0] into newGroup
            orderby newGroup.Key
            select newGroup;

        // Execute the query.
        Console.WriteLine(Environment.NewLine + "sortedGroups:");
        foreach (var studentGroup in sortedGroups)
        {
            Console.WriteLine(studentGroup.Key);
            foreach (var student in studentGroup)
            {
                Console.WriteLine("   {0}, {1}", student.Last, student.First);
            }
        }

        // Keep the console window open in debug mode
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}
/* Output:  
sortedStudents:
Garcia Cesar
Garcia Debra
Mortensen Sven
O'Donnell Claire
Omelchenko Svetlana

sortedGroups:
G
   Garcia, Cesar
   Garcia, Debra
M
   Mortensen, Sven
O
   O'Donnell, Claire
   Omelchenko, Svetlana
*/


10. 컴파일 타임에 orderby 절은 OrderBy<TSource, TKey> 메서드를 호출로 변환(translate)합니다.

11. orderby 절의 여러 키는 ThenBy<TSource, TKey> 메서드 호출로 변환됩니다.





partial


1. 부분 형식(Partial Type) 정의를 사용하면 클래스, 구조체 또는 인터페이스의 정의를 여러 파일로 분할할 수 있습니다.


File1.cs: namespace PC

{ partial class A { int num = 0; void MethodA() { } partial void MethodC(); } }


Fiel2.cs:
namespace PC
{
    partial class A
    {
        void MethodB() { }
        partial void MethodC() { }
    }
}


2. 클래스, 구조체, 인터페이스 형식을 여러 파일로 분할(split)하면 대형 프로젝트(large projects)에서 제공된 것과 같이 자동으로 생성된 코드를 작업할 때 유용할 수 있습니다.

3. 부분 형식에는 부분 메서드가 포함될 수 있습니다.

4. 자세한 내용은 Partial 클래스 및 메서드를 참조하십시오.





partial


1. 부분 메서드(Partial Method)에는 부분 형식(Partial Type)의 일부분에 정의된 시그니처와 다른 형식의 부분에 정의된 구현이 있습니다.

2. 클래스 디자이너는 부분 메서드를 사용하여 이벤트 처리기와 유사한 메서드 후크를 제공하여 개발자가 구현 여부를 결정할 수 있습니다.

3. 개발자가 구현을 제공하지 않는 경우 컴파일러에서는 컴파일 타임에 시그니처를 제거합니다.

4. 부분 메서드에는 다음과 같은 조건이 적용됩니다.

    1) 부분 형식(Partial Type)의 두 부분에서 시그니처가 일치해야 합니다.

    2) 해당 메서드는 void를 반환해야 합니다

    3) 어떠한 액세스 한정자도 사용할 수 없습니다. 부분 메서드는 암시적으로 private입니다.

5. 다음 예제에서는 부분 클래스의 두 부분에서 정의된 부분 메서드를 보여 줍니다.


namespace PM
{
    partial class A
    {
        partial void OnSomethingHappened(string s);
    }

    // This part can be in a separate file.
    partial class A
    {
        // Comment out this method and the program
        // will still compile.
        partial void OnSomethingHappened(String s)
        {
            Console.WriteLine("Something happened: {0}", s);
        }
    }
}


6. 자세한 내용은 Partial 클래스 및 메서드를 참조하십시오.





remove


1. remove 컨텍스트 키워드는 클라이언트 코드가 사용자의 이벤트 구독을 취소할 때(unsubscribe) 호출되는 사용자 지정 이벤트 접근자를 정의하는 데 사용됩니다.

2. 사용자 지정 remove 접근자를 제공하는 경우에는 add 접근자도 제공해야 합니다.

3. 다음 예제에서는 사용자 지정 add 및 remove 접근자가 있는 이벤트를 보여 줍니다.

4. 전체 예제를 보려면 방법: 인터페이스 이벤트 구현을 참조하십시오.


class Events : IDrawingObject
{
    event EventHandler PreDrawEvent;

    event EventHandler IDrawingObject.OnDraw
    {
        add
        {
            lock (PreDrawEvent)
            {
                PreDrawEvent += value;
            }
        }
        remove
        {
            lock (PreDrawEvent)
            {
                PreDrawEvent -= value;
            }
        }
    }

}


5. 일반적으로 자체 사용자 지정 이벤트 접근자를 제공할 필요는 없습니다.

6. 대부분의 경우 이벤트를 선언할 때 컴파일러에서 자동으로 생성되는 접근자로도 충분합니다.





select


1. 쿼리 식에서 select 절은 쿼리가 실행될 때 생성할 값의 형식을 지정합니다.

2. 결과는 앞의 모든 절select 절 자체의 모든 식을 기준을 합니다.

3. 쿼리 식은 select 절 또는 group 절로 끝나야 합니다.

4. 다음 예제에서는 쿼리 식에서의 간단한 select 절을 보여 줍니다.


class SelectSample1
{   
    static void Main()
    {           
        //Create the data source
        List<int> Scores = new List<int>() { 97, 92, 81, 60 };

        // Create the query.
        IEnumerable<int> queryHighScores =
            from score in Scores
            where score > 80
            select score;

        // Execute the query.
        foreach (int i in queryHighScores)
        {
            Console.Write(i + " ");
        }            
    }
}
//Output: 97 92 81


5. select 절에 의해 생성된 시퀀스의 형식은 쿼리 변수 queryHighScores의 형식을 결정합니다.

6. 가장 간단하게는(In the simplest case), select 절이 범위 변수만 지정합니다.

7. 이로 인해 반환된 시퀀스에 데이터 소스와 동일한 형식의 요소가 포함됩니다.

8. 자세한 내용은 Type Relationships in LINQ Query Operations를 참조하십시오.

9. 그러나 select 절에서는 소스 데이터를 새 형식으로 변환(transforming)(또는 프로젝팅)하는 강력한 메커니즘을 제공합니다.

10. 자세한 내용은 LINQ를 통한 데이터 변환을 참조하십시오.

11. 다음 예제에서는 select 절의 여러 가지 가능한 형식(all the different forms)을 모두 보여 줍니다.

12. 각 쿼리에서 select 절과 쿼리 변수의 형식(studentQuery1 및 studentQuery2 등(and so on) 사이의 관계를 참고하십시오.


class SelectSample2
    {
        // Define some classes
        public class Student
        {
            public string First { get; set; }
            public string Last { get; set; }
            public int ID { get; set; }
            public List<int> Scores;
            public ContactInfo GetContactInfo(SelectSample2 app, int id)
            {
                ContactInfo cInfo =
                    (from ci in app.contactList
                    where ci.ID == id
                    select ci)
                    .FirstOrDefault();

                return cInfo;
            }

            public override string ToString()
            {
                return First + " " + Last + ":" + ID;
            }
        }

        public class ContactInfo
        {
            public int ID { get; set; }
            public string Email { get; set; }
            public string Phone { get; set; }
            public override string ToString() { return Email + "," + Phone; }
        }

        public class ScoreInfo
        {
            public double Average { get; set; }
            public int ID { get; set; }
        }

        // The primary data source
        List<Student> students = new List<Student>()
        {
             new Student {First="Svetlana", Last="Omelchenko", ID=111, Scores= new List<int>() {97, 92, 81, 60}},
             new Student {First="Claire", Last="O'Donnell", ID=112, Scores= new List<int>() {75, 84, 91, 39}},
             new Student {First="Sven", Last="Mortensen", ID=113, Scores= new List<int>() {88, 94, 65, 91}},
             new Student {First="Cesar", Last="Garcia", ID=114, Scores= new List<int>() {97, 89, 85, 82}},
        };

        // Separate data source for contact info.
        List<ContactInfo> contactList = new List<ContactInfo>()
        {
            new ContactInfo {ID=111, Email="SvetlanO@Contoso.com", Phone="206-555-0108"},
            new ContactInfo {ID=112, Email="ClaireO@Contoso.com", Phone="206-555-0298"},
            new ContactInfo {ID=113, Email="SvenMort@Contoso.com", Phone="206-555-1130"},
            new ContactInfo {ID=114, Email="CesarGar@Contoso.com", Phone="206-555-0521"}
        };


        static void Main(string[] args)
        {
            SelectSample2 app = new SelectSample2();

            // Produce a filtered sequence of unmodified Students.
            IEnumerable<Student> studentQuery1 =
                from student in app.students
                where student.ID > 111
                select student;

            Console.WriteLine("Query1: select range_variable");
            foreach (Student s in studentQuery1)
            {
                Console.WriteLine(s.ToString());
            }

            // Produce a filtered sequence of elements that contain
            // only one property of each Student.
            IEnumerable<String> studentQuery2 =
                from student in app.students
                where student.ID > 111
                select student.Last;

            Console.WriteLine("\r\n studentQuery2: select range_variable.Property");
            foreach (string s in studentQuery2)
            {
                Console.WriteLine(s);
            }

            // Produce a filtered sequence of objects created by
            // a method call on each Student.
            IEnumerable<ContactInfo> studentQuery3 =
                from student in app.students
                where student.ID > 111
                select student.GetContactInfo(app, student.ID);

            Console.WriteLine("\r\n studentQuery3: select range_variable.Method");
            foreach (ContactInfo ci in studentQuery3)
            {
                Console.WriteLine(ci.ToString());
            }

            // Produce a filtered sequence of ints from
            // the internal array inside each Student.
            IEnumerable<int> studentQuery4 =
                from student in app.students
                where student.ID > 111
                select student.Scores[0];

            Console.WriteLine("\r\n studentQuery4: select range_variable[index]");
            foreach (int i in studentQuery4)
            {
                Console.WriteLine("First score = {0}", i);
            }

            // Produce a filtered sequence of doubles 
            // that are the result of an expression.
            IEnumerable<double> studentQuery5 =
                from student in app.students
                where student.ID > 111
                select student.Scores[0] * 1.1;

            Console.WriteLine("\r\n studentQuery5: select expression");
            foreach (double d in studentQuery5)
            {
                Console.WriteLine("Adjusted first score = {0}", d);
            }

            // Produce a filtered sequence of doubles that are
            // the result of a method call.
            IEnumerable<double> studentQuery6 =
                from student in app.students
                where student.ID > 111
                select student.Scores.Average();

            Console.WriteLine("\r\n studentQuery6: select expression2");
            foreach (double d in studentQuery6)
            {
                Console.WriteLine("Average = {0}", d);
            }

            // Produce a filtered sequence of anonymous types
            // that contain only two properties from each Student.
            var studentQuery7 =
                from student in app.students
                where student.ID > 111
                select new { student.First, student.Last };

            Console.WriteLine("\r\n studentQuery7: select new anonymous type");
            foreach (var item in studentQuery7)
            {
                Console.WriteLine("{0}, {1}", item.Last, item.First);
            }

            // Produce a filtered sequence of named objects that contain
            // a method return value and a property from each Student.
            // Use named types if you need to pass the query variable 
            // across a method boundary.
            IEnumerable<ScoreInfo> studentQuery8 =
                from student in app.students
                where student.ID > 111
                select new ScoreInfo
                {
                    Average = student.Scores.Average(),
                    ID = student.ID
                };

            Console.WriteLine("\r\n studentQuery8: select new named type");
            foreach (ScoreInfo si in studentQuery8)
            {
                Console.WriteLine("ID = {0}, Average = {1}", si.ID, si.Average);
            }

            // Produce a filtered sequence of students who appear on a contact list
            // and whose average is greater than 85.
            IEnumerable<ContactInfo> studentQuery9 =
                from student in app.students
                where student.Scores.Average() > 85
                join ci in app.contactList on student.ID equals ci.ID
                select ci;

            Console.WriteLine("\r\n studentQuery9: select result of join clause");
            foreach (ContactInfo ci in studentQuery9)
            {
                Console.WriteLine("ID = {0}, Email = {1}", ci.ID, ci.Email);
            }

            // Keep the console window open in debug mode
            Console.WriteLine("Press any key to exit.");
            Console.ReadKey();
            }
        }
    /* Output
        Query1: select range_variable
        Claire O'Donnell:112
        Sven Mortensen:113
        Cesar Garcia:114

        studentQuery2: select range_variable.Property
        O'Donnell
        Mortensen
        Garcia

        studentQuery3: select range_variable.Method
        ClaireO@Contoso.com,206-555-0298
        SvenMort@Contoso.com,206-555-1130
        CesarGar@Contoso.com,206-555-0521

        studentQuery4: select range_variable[index]
        First score = 75
        First score = 88
        First score = 97

        studentQuery5: select expression
        Adjusted first score = 82.5
        Adjusted first score = 96.8
        Adjusted first score = 106.7

        studentQuery6: select expression2
        Average = 72.25
        Average = 84.5
        Average = 88.25

        studentQuery7: select new anonymous type
        O'Donnell, Claire
        Mortensen, Sven
        Garcia, Cesar

        studentQuery8: select new named type
        ID = 112, Average = 72.25
        ID = 113, Average = 84.5
        ID = 114, Average = 88.25

        studentQuery9: select result of join clause
        ID = 114, Email = CesarGar@Contoso.com
*/


13. 앞 예제의 studentQuery8와 같이 반환된 시퀀스의 요소가 소스 요소의 속성의 하위 집합(subset)만 포함하도록 지정해야 하는 경우가 있습니다.

14. 반환된 시퀀스를 가능한 한 작게 유지하면 메모리 요구 사항을 줄이고 쿼리 실행 속도를 높일 수 있습니다

15. select 절에서 익명 형식을 만들고 개체 이니셜라이저를 사용하여 소스 요소의 적절한 속성으로 익명 형식을 초기화하면 이 작업을 수행할 수 있습니다.

16. 이 작업을 수행하는 방법에 대한 예제는 개체 및 컬렉션 이니셜라이저를 참조하십시오.

17. 컴파일 타임에 select 절은 Select<TSource, TResult> 표준 쿼리 연산자에 대한 메서드 호출로 변환됩니다.





set


1. set 키워드는 속성 값 또는 인덱서 요소를 할당하는 접근자 메서드를 속성 또는 인덱스에 정의합니다.

2. 자세한 내용은 속성, 자동으로 구현된 속성, 인덱서를 참조하십시오.

3. 다음은 Seconds라는 속성에 대한 set 접근자의 예입니다.


class TimePeriod
{
    private double _seconds;
    public double Seconds
    {
        get { return _seconds; }
        set { _seconds = value; }
    }
}


4. 다음은 자동으로 구현된 속성의 set 접근자에 대한 예제입니다.


class TimePeriod2
{
    public double Hours { get; set; }
}





value


1. 키워드 value는 일반 속성 선언의 set 접근자에 사용되며, 메서드의 입력 매개 변수와 비슷합니다.

2. 단어(the word) value는 클라이언트 코드에서 속성에 할당하는 값을 참조(reference)합니다.

3. 다음 예제에서 MyDerivedClass에는 Name이라는 속성이 있습니다.

4. 이 속성은 value 매개 변수를 사용하여 지원 필드 name에 새 문자열을 할당합니다.

5. 클라이언트 코드 측면에서(From the point of view of client code) 연산은 단순 할당으로 작성됩니다.


class MyBaseClass
{
    // virtual auto-implemented property. Overrides can only
    // provide specialized behavior if they implement get and set accessors.
    public virtual string Name { get; set; }

    // ordinary virtual property with backing field
    private int num;
    public virtual int Number
    {
        get { return num; }
        set { num = value; }
    }
}


class MyDerivedClass : MyBaseClass
{
    private string name;

   // Override auto-implemented property with ordinary property
   // to provide specialized accessor behavior.
    public override string Name
    {
        get
        {
            return name;
        }
        set
        {
            if (value != String.Empty)
            {
                name = value;
            }
            else
            {
                name = "Unknown";
            }
        }
    }

}


6. value 사용에 대한 자세한 내용은 속성을 참조하십시오.





var


1. Visual C# 3.0 부터는(Beginning) 메서드 범위에서 선언된 변수가 암시적 형식 var를 가질 수 있습니다.

2. 암시적으로 형식화된 지역 변수는 형식 자체를 선언했던 것처럼 강력하게 형식화되었지만 컴파일러에게 형식을 결정합니다.


var i = 10; // implicitly typed
int i = 10; //explicitly typed

 

3. 자세한 내용은 암시적으로 형식화된 지역 변수LINQ 쿼리 작업의 형식 관계를 참조하십시오.

4. 다음 예제에서는 두 개의 쿼리 식을 보여 줍니다.

5. 첫번째 식에서 var의 사용은 허용(permit)되나 쿼리 결과의 형식이 IEnumerable<string>로 명확하게 지정되기(state) 때문에 필요한 것은 아닙니다.

6. 그러나 두 번째 식에서는 결과가 익명 형식의 컬렉션이고 형식의 이름이 컴파일러 자체 이외에는 액세스할 수 없으므로 var를 사용해야 합니다.

7. 예제 #2에서는 foreach 반복 변수 item은 암시적으로도 형식화되어야 합니다.


// Example #1: var is optional because
// the select clause specifies a string
string[] words = { "apple", "strawberry", "grape", "peach", "banana" };
var wordQuery = from word in words
                where word[0] == 'g'
                select word;

// Because each element in the sequence is a string, 
// not an anonymous type, var is optional here also.
foreach (string s in wordQuery)
{
    Console.WriteLine(s);
}

// Example #2: var is required because
// the select clause specifies an anonymous type
var custQuery = from cust in customers
                where cust.City == "Phoenix"
                select new { cust.Name, cust.Phone };

// var must be used because each item 
// in the sequence is an anonymous type
foreach (var item in custQuery)
{
    Console.WriteLine("Name={0}, Phone={1}", item.Name, item.Phone);
}






where(제네릭 형식 제약 조건)


1. 제네릭 형식 정의에서 where 절은 제네릭 선언에 정의된 형식 매개 변수의 인수로 사용할 수 있는 형식에 대해 제약 조건(constraints)을 지정하는 데 사용됩니다.

2. 예를 들어 다음과 같이 형식 매개 변수 T가 IComparable<T> 인터페이스를 구현하도록 제네릭 클래스 MyGenericClass를 선언할 수 있습니다.


public class MyGenericClass<T> where T:IComparable { }


System_CAPS_note참고

쿼리 식의 where 절에 대한 자세한 내용은 where 절(C# 참조)을 참조하십시오.

3. where 절에는 인터페이스 제약 조건 외의 기본 클래스 제약 조건도 포함될 수 있습니다.

4. 이 제약 조건은 지정된 클래스를 기본 클래스로 갖거나 지정된 클래스 자체인 형식만 해당 제네릭 형식 인수로 사용할 수 있도록 제한합니다.

5. 이러한 제약 조건을 사용할 경우에는 해당 형식 매개 변수에 대한 다른 모든 제약 조건 앞에 사용해야 합니다.


class MyClass<T, U>
    where T : class
    where U : struct
{ }


6. where 절에는 생성자 제약 조건도 포함될 수 있습니다.

7. new 연산자를 사용하여 형식 매개 변수의 인스턴스를 만들 수 있지만 이렇게 하려면 형식 매개 변수를 생성자 제약 조건 new()로 제한해야 합니다.

8. new() 제약 조건을 사용하면 컴파일러에서는 제공된 모든 형식 인수가 액세스 가능하고 매개 변수 없는(또는 기본) 생성자를 가져야 한다는 것을 알 수 있습니다.


public class MyGenericClass<T> where T : IComparable, new()
{
    // The following line is not possible without new() constraint:
    T item = new T();
}


9. new() 제약 조건은 where 절의 마지막에 나와 있습니다.

10. 형식 매개 변수가 여러 개이면 다음 예제와 같이 where 절을 각 형식 매개 변수마다 하나씩 사용합니다.


interface IMyInterface
{
}

class Dictionary<TKey, TVal>
    where TKey : IComparable, IEnumerable
    where TVal : IMyInterface
{
    public void Add(TKey key, TVal val)
    {
    }
}


11. 다음과 같이 제네릭 메서드의 형식 매개 변수에 제약 조건을 연결할(attach) 수도 있습니다.


public bool MyMethod<T>(T t) where T : IMyInterface { }


12. 대리자에 대한 형식 매개 변수 제약 조건을 설명하기 위한 구문은 메서드에 사용하는 구문과 동일합니다.


delegate T MyDelegate<T>() where T : new()


13. 제네릭 대리자에 대한 자세한 내용은 제네릭 대리자를 참조하십시오.

14. 제약 조건의 구문 및 사용 방법에 대한 자세한 내용은 형식 매개 변수에 대한 제약 조건을 참조하십시오.





where 절


1. where 절은 쿼리 식에서 반환할 데이터 소스의 요소를 쿼리 식에 지정하는 데 사용됩니다.

2. 이 절은 범위 변수로 참조되는 각 소스 요소에 Boolean 조건(조건자(predicate))을 적용하고, 지정한 조건이 true인 요소를 반환합니다.

3. 쿼리 식 하나에는 where 절을 여러 개 포함할 수 있으며 절 하나에는 조건자 하위 식(predicate subexpressions)을 여러 개 포함할 수 있습니다.

4. 다음 예제에서 where 절은 5 미만의(less than five) 숫자만 필터링합니다.

5. where 절을 제거하면 데이터 소스에서 모든 숫자가 반환됩니다.

6. 여기서 num < 5 식은 각 요소에 적용되는 조건자입니다


class WhereSample
{
    static void Main()
    {   
        // Simple data source. Arrays support IEnumerable<T>.
        int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };

        // Simple query with one predicate in where clause.
        var queryLowNums =
            from num in numbers
            where num < 5
            select num;

        // Execute the query.
        foreach (var s in queryLowNums)
        {
            Console.Write(s.ToString() + " ");
        }
    }
}
//Output: 4 1 3 2 0


7. where 절 하나에는 && 및 || 연산자를 사용하여 조건자를 필요한 만큼 지정할 수 있습니다.

8. 다음 예제에서는 쿼리에 조건자 두 개를 지정하여 5미만의 짝수만(only the even numbers) 선택합니다.


class WhereSample2
{
    static void Main()
    {
        // Data source.
        int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };

        // Create the query with two predicates in where clause.
        var queryLowNums2 =
            from num in numbers
            where num < 5 && num % 2 == 0
            select num;

        // Execute the query
        foreach (var s in queryLowNums2)
        {
            Console.Write(s.ToString() + " ");
        }
        Console.WriteLine();

        // Create the query with two where clause.
        var queryLowNums3 =
            from num in numbers
            where num < 5
            where num % 2 == 0
            select num;

        // Execute the query
        foreach (var s in queryLowNums3)
        {
            Console.Write(s.ToString() + " ");
        }

    }
}
// Output: 
// 4 2 0
// 4 2 0


9. where 절에는 Boolean 값을 반환하는 메서드를 하나 이상 포함할 수 있습니다.

10. 다음 예제에서는 where 절에 메서드를 사용하여 범위 변수의 현재 값이 짝수인지 홀수인지 결정합니다.


class WhereSample3
{       
    static void Main()
    {
        // Data source
        int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };

        // Create the query with a method call in the where clause.
        // Note: This won't work in LINQ to SQL unless you have a
        // stored procedure that is mapped to a method by this name.
        var queryEvenNums =
            from num in numbers
            where IsEven(num)
            select num;

         // Execute the query.
        foreach (var s in queryEvenNums)
        {
            Console.Write(s.ToString() + " ");
        }
    }

    // Method may be instance method or static method.
    static bool IsEven(int i)
    {
        return i % 2 == 0;
    }    
}
//Output: 4 8 6 2 0


11. where 절은 필터링 메커니즘입니다.

12. 쿼리 식의 모든 위치에(positioned almost anywhere) 사용할 수 있지만 첫 번째 또는 마지막 절은 될 수 없습니다.

13. where 절은 소스 요소 필터링을 그룹화 전에 할지, 그룹화 후에 할지에 따라 group 절 앞이나 뒤에 올 수 있습니다.

14. 지정한 조건자가 데이터 소스의 요소에 대해 올바르지 않으면 컴파일 타임 오류가 발생합니다.

15. 이는 LINQ의 강력한 형식 검사(the strong type-checking) 기능의 장점(benefit) 중 하나입니다.

16. 컴파일 타임에 where 키워드는 Where 표준 쿼리 연산자 메서드에 대한 호출로 변환됩니다.






yield


1. 여러분이 문장에 yield 키워드를 사용하면, 거기에 나타난 메서드, 연산자, get 접근자가 반복기(iterator)라는 것을 표시(indicate)하는 것입니다.

2. yield를 사용하여 반복기를 정의할 경우 사용자 지정 컬렉션 형식에 IEnumerableIEnumerator 패턴을 구현하면 명시적 추가 클래스(열거형의 상태를 보관하는 클래스, 예제는 IEnumerator<T> 참조)를 사용하지 않아도 됩니다.

3. 다음 예제에서는 yield 문장의 두가지 형태를 보여줍니다.


yield return <expression>;
yield break;


4. yield return 문은 각 요소를 한 번에 하나씩(one at a time) 반환하기 위해 사용합니다

5. 여러분은 foreach 문 또는 LINQ 쿼리를 사용할 때 반복기 메서드를 소비합니다.

6. foreach 루프의 각 반복마다 반복기 메서드를 호출합니다.

7. 반복기 메서드에서 yield return 문에 도달한 경우, expression이 반환되고, 코드의 현재 위치가 유지(retain)됩니다.

8. 다음 번의 반복기 함수 호출 시에, 해당 위치부터 실행이 재개됩니다.

9. 여러분은 해당 반복을 종료하기 위해 yield break 문을 사용할 수 있습니다.

10. 반복기에 대한 자세한 내용은 반복기를 참조하십시오.

<반복기 메서드 및 Get 접근자>

11. 반복기 선언은 다음 요구 사항을 충족해야 합니다(meet the following requirements).

12. 반환 형식은 IEnumerable, IEnumerable<T>, IEnumerator, IEnumerator<T>가 되어야 합니다.

13. 선언에 ref 또는 out 매개 변수가 들어갈 수 없습니다.

14. IEnumerable 또는 IEnumerator를 반환하는 반복기의 yield 형식은 object입니다.

15. 반복기가 IEnumerable<T> 또는 IEnumerator<T>를 반환할 경우 yield return 문의 식 형식에서 제네릭 형식 매개 변수로 암시적 변환이 있어야 합니다.

16. 다음 특징을 지닌 메서드에 yield return 또는 yield break 문을 포함할 수 없습니다.

    1) 무명 메서드. 자세한 내용은 무명 메서드를 참조하십시오.

    2) unsafe 블록을 포함하는 메서드. 자세한 내용은 unsafe를 참조하십시오.

<예외 처리>

17. yield return 문은 try-catch 블록 안에 입력할 수 없습니다.

18. yield return 문은 try-finally 문의 try 블록 내에 입력할 수 있습니다.

19. yield break 문은 try 또는 catch 블록 안에서 사용할 수 있으나 finally 블록 안에서는 사용할 수 없습니다.

20. foreach 본문 (반복기 메서드 바깥)에서 예외를 throw하는 경우, 반복기 메서드에 있는 finally 블록이 실행됩니다.

21. 다음 코드는 반복기 메서드로부터 IEnumerable<string>을 반환하고 해당 요소를 반복합니다.


IEnumerable<string> elements = MyIteratorMethod();
foreach (string element in elements)
{
   …
}


22. MyIteratorMethod 호출은 메서드의 본문을 실행하지 않습니다.

23. 대신 해당 호출은 IEnumerable<string>을 반환해서 elements 변수에 담습니다.

24. foreach 루프 반복 중에, elements에 대한 MoveNext 메서드가 호출됩니다.

25. 이 호출은 다음 yield return 문에 도달할 때가지 MyIteratorMethod의 본문을 실행합니다.

26. yield return 문의 반환 식은, 루프 본문에서 소비하는 element 변수의 값을 결정할 뿐 아니라 IEnumeragble<string>인 elements의 Current 속성 또한 결정합니다.

27. foreach 루프의 차후 반복마다 전에 중지했던(left off) 곳부터 반복기 본문의 실행을 재개하고 yield return 문에 도달하면 중지됩니다.

28. foreach 루프는 반복기 메서드의 끝 또는 yield break 문에 도달했을 때 종료됩니다.

<예제>

29. 다음 에제는 for 루프 안에 yield return 문이 있습니다.

30. Process 내에 foreach 문의 본문을 반복할 때마다, Power 반복기 함수로의 호출이 발생합니다.

31. 반복기 함수를 호출할 때마다, 다음번 for 루프를 반복할 때의 yield return 문 실행까지 진행합니다proceed).

32. 해당 반복기 메서드의 반환 형식은 반복기 인터페이스 형식인 IEnumerable입니다.

33. 반복기 메서드가 호출되면 숫자의 거듭제곱(the powers)을 포함하는 열거 가능 개체를 반환합니다.


public class PowersOf2
{
    static void Main()
    {
        // Display powers of 2 up to the exponent of 8:
        foreach (int i in Power(2, 8))
        {
            Console.Write("{0} ", i);
        }
    }

    public static System.Collections.Generic.IEnumerable<int> Power(int number, int exponent)
    {
        int result = 1;

        for (int i = 0; i < exponent; i++)
        {
            result = result * number;
            yield return result;
        }
    }

    // Output: 2 4 8 16 32 64 128 256
}


34. 다음 예제는 반복기인 get 접근자를 소개합니다.

35. 예제에서 각 yield return 문은 사용자 정의  클래스의 인스턴스를 반환합니다.


public static class GalaxyClass
{
    public static void ShowGalaxies()
    {
        var theGalaxies = new Galaxies();
        foreach (Galaxy theGalaxy in theGalaxies.NextGalaxy)
        {
            Debug.WriteLine(theGalaxy.Name + " " + theGalaxy.MegaLightYears.ToString());
        }
    }

    public class Galaxies
    {

        public System.Collections.Generic.IEnumerable<Galaxy> NextGalaxy
        {
            get
            {
                yield return new Galaxy { Name = "Tadpole", MegaLightYears = 400 };
                yield return new Galaxy { Name = "Pinwheel", MegaLightYears = 25 };
                yield return new Galaxy { Name = "Milky Way", MegaLightYears = 0 };
                yield return new Galaxy { Name = "Andromeda", MegaLightYears = 3 };
            }
        }

    }

    public class Galaxy
    {
        public String Name { get; set; }
        public int MegaLightYears { get; set; }
    }
}






'프로그래밍 > C#' 카테고리의 다른 글

제네릭  (0) 2016.06.11
C# 기타  (0) 2016.06.10
C# 키워드 T~Z  (0) 2016.06.03
C# 키워드 O~S  (0) 2016.05.31
C# 키워드 F~N  (0) 2016.05.21
:
Posted by 지훈2
2016. 6. 3. 19:48

C# 키워드 T~Z 프로그래밍/C#2016. 6. 3. 19:48

this


1. this 키워드는 클래스의 현재 인스턴스를 가리키며 확장 메서드의 첫째 매개 변수에 대한 한정자로도 사용됩니다.

System_CAPS_note참고

이 문서에서는 this를 클래스 인스턴스와 함게 사용하는 방법을 설명합니다. 확장 메서드에서 이를 사용하는 방법에 대한 자세한 내용은 확장 메서드(C# 프로그래밍 가이드)를 참조하십시오.

2. 일반적으로 this 키워드는 다음과 같이 사용됩니다.

    1) 예를 들어, 비슷한 이름으로 숨겨진 멤버를 한정하는 방법은 다음과 같습니다.


public Employee(string name, string alias)
{
    // Use this to qualify the fields, name and alias:
    this.name = name;
    this.alias = alias;
}


3. 개체를 다른 메서드의 매개 변수로 전달하는 방법은 다음과 같습니다.


CalcTax(this);


4. 인덱서를 선언하는 방법은 다음과 같습니다.


public int this[int param]
{
    get { return array[param]; }
    set { array[param] = value; }
}


5. 클래스 수준에서 작성되고 개체의 일부로 포함되지 않는 정적 멤버 함수에는 this 포인터가 없습니다.

6. 정적 메서드에서 this를 참조하려고 하면 오류가 발생합니다.

7. 이 예제에서 this는 비슷한 이름으로 숨겨진 Employee 클래스 멤버(name, alias)를 한정(qualify)하는 데 사용됩니다.

8. 또한 다른 클래스에 속한 CalcTax 메서드로 개체를 전달하는 데 사용됩니다.


class Employee
{
    private string name;
    private string alias;
    private decimal salary = 3000.00m;

    // Constructor:
    public Employee(string name, string alias)
    {
        // Use this to qualify the fields, name and alias:
        this.name = name;
        this.alias = alias;
    }
    // Printing method:
    public void printEmployee()
    {
        Console.WriteLine("Name: {0}\nAlias: {1}", name, alias);
        // Passing the object to the CalcTax method by using this:
        Console.WriteLine("Taxes: {0:C}", Tax.CalcTax(this));
    }

    public decimal Salary
    {
        get { return salary; }
    }
}

class Tax
{
    public static decimal CalcTax(Employee E)
    {
        return 0.08m * E.Salary;
    }
}

class MainClass
{
    static void Main()
    {
        // Create objects:
        Employee E1 = new Employee("Mingda Pan", "mpan");

        // Display results:
        E1.printEmployee();
    }
}
/*
Output:
    Name: Mingda Pan
    Alias: mpan
    Taxes: $240.00
 */




throw


1. throw 문은 프로그램 실행 중에 비정상적인(anomalous) 상황(예외)이 발생한 경우 이를 알리는 데(signal) 사용됩니다.

2. 아래 예제에서 볼 수 있는 것처럼 throw된 예제는 System.Exception에서 바생된 클래스의 개체입니다.


class MyException : System.Exception {}
// ...
throw new MyException();


3. 일반적으로 throw 문은 try-catch 또는 try-finally 문과 함께 사용됩니다.

4. throw 문을 catch 블록에 사용하여 catch 블록에서 catch한 예외를 다시 throw할 수 있습니다.

5. 이 경우에 throw 문은 예외 피연산자를 사용하지 않습니다.

6. 자세한 내용 및 예제를 보려면 try-catch 및 방법: 명시적으로 예외 Throw를 참조하십시오.

7. 아래 예제는 throw 문을 사용하여 예외를 throw하는 방법을 보여줍니다.


public class ThrowTest2
{

    static int GetNumber(int index)
    {
        int[] nums = { 300, 600, 900 };
        if (index > nums.Length)
        {
            throw new IndexOutOfRangeException();
        }
        return nums[index];

    }
    static void Main() 
    {
        int result = GetNumber(3);

    }
}
/*
    Output:
    The System.IndexOutOfRangeException exception occurs.
*/


8. try-catch방법: 명시적으로 예외 Throw에서 예제를 참조하십시오.





true 연산자


1. 피연산자가 true임을 나타낼 경우 bool 값 true를 반환하고, 그렇지 않을 경우 false를 반환합니다.

2. C# 2.0 이전 버전에서는 true 및 false 연산자를 사용해서 SqlBool과 같은 형식과 호환되는 사용자 정의 null 허용 값 형식을 만들었습니다.

3. 그러나 이 버전에서는 null 허용 값 형식에 대한 지원이 기본적으로 제공되므로 가능하면 true 및 false 연산자를 오버로드하는 대신 null 허용 값 형식을 사용해야 합니다.

4. 자세한 내용은 nullable 형식을 참조하십시오.

5. nullable 부을을 사용하면 a != b 식은 두 값 중 하나 이상이 null일 수 있으므로 !(a == b)과 반드시 일치하지 않습니다(is not necessarily equal to).

6. 식의 null 값을 올바르게 식별하려면 true 및 false 연산자를 개별적으로 오버로드해야 합니다

7. 다음 예제에서는 true 및 false 연산자를 오버로드하여 사용하는 방법을 보여 줍니다.


// For example purposes only. Use the built-in nullable bool 
// type (bool?) whenever possible. public struct DBBool { // The three possible DBBool values. public static readonly DBBool Null = new DBBool(0); public static readonly DBBool False = new DBBool(-1); public static readonly DBBool True = new DBBool(1); // Private field that stores –1, 0, 1 for False, Null, True. sbyte value; // Private instance constructor. The value parameter must be –1, 0, or 1. DBBool(int value) { this.value = (sbyte)value; } // Properties to examine the value of a DBBool. Return true if this // DBBool has the given value, false otherwise. public bool IsNull { get { return value == 0; } } public bool IsFalse { get { return value < 0; } } public bool IsTrue { get { return value > 0; } } // Implicit conversion from bool to DBBool. Maps true to DBBool.True and // false to DBBool.False. public static implicit operator DBBool(bool x) { return x ? True : False; } // Explicit conversion from DBBool to bool. Throws an exception if the // given DBBool is Null; otherwise returns true or false. public static explicit operator bool(DBBool x) { if (x.value == 0) throw new InvalidOperationException(); return x.value > 0; } // Equality operator. Returns Null if either operand is Null; otherwise // returns True or False. public static DBBool operator ==(DBBool x, DBBool y) { if (x.value == 0 || y.value == 0) return Null; return x.value == y.value ? True : False; } // Inequality operator. Returns Null if either operand is Null; otherwise // returns True or False. public static DBBool operator !=(DBBool x, DBBool y) { if (x.value == 0 || y.value == 0) return Null; return x.value != y.value ? True : False; } // Logical negation operator. Returns True if the operand is False, Null // if the operand is Null, or False if the operand is True. public static DBBool operator !(DBBool x) { return new DBBool(-x.value); } // Logical AND operator. Returns False if either operand is False, // Null if either operand is Null, otherwise True. public static DBBool operator &(DBBool x, DBBool y) { return new DBBool(x.value < y.value ? x.value : y.value); } // Logical OR operator. Returns True if either operand is True, // Null if either operand is Null, otherwise False. public static DBBool operator |(DBBool x, DBBool y) { return new DBBool(x.value > y.value ? x.value : y.value); } // Definitely true operator. Returns true if the operand is True, false // otherwise. public static bool operator true(DBBool x) { return x.value > 0; } // Definitely false operator. Returns true if the operand is False, false // otherwise. public static bool operator false(DBBool x) { return x.value < 0; } public override bool Equals(object obj) { if (!(obj is DBBool)) return false; return value == ((DBBool)obj).value; } public override int GetHashCode() { return value; } public override string ToString() { if (value > 0) return "DBBool.True"; if (value < 0) return "DBBool.False"; return "DBBool.Null"; } }


8. true 및 false 연산자를 오버로드하는 형식은 if, do, while, for 문과 조건식에서 제어식(the controlling expression)에 사용할 수 있습니다.

9. true 연산자를 정의하는 형식은 false 연산자도 정의해야 합니다.

10. 한 형식으로 조건부 논리 연산자(&& 및 ||)를 직접 오버로드할 수 없지만, 일반적인 논리 연산자와 true 및 false 연산자를 오버로드하면 조건부 논리 연산자(the conditional logical operators)를 오버로드한 것과 같은 결과(an equivalent effect)를 얻을 수 있습니다.





true 리터럴


1. 부울(Boolean) 값 true를 나타냅니다.


class TrueTest
{
    static void Main() 
    {
        bool a = true;
        Console.WriteLine( a ? "yes" : "no" );
    }
}
/*
Output:
yes
*/





try


1. catch 참조





typeof


1. 형식에 대한 System.Type 개체를 얻는 데 사용됩니다.

2. typeof 식의 형식은 다음과 같습니다.


System.Type type = typeof(int);


3. 식의 런타임 형식을 얻으려면 다음 예제와 같이 .NET Framework 메서드 GetType을 사용합니다.


int i = 0;
System.Type type = i.GetType();


4. typeof 연산자는 오버로드되지 않습니다.

5. typeof 연산자는 열린 제네릭 형식에도 사용할 수 있습니다.

6. 형식 매개 변수가 둘 이상인 형식을 지정할 때는 적절한(appropriate) 수의 쉼표를 사용해야 합니다.

7. 다음 예제에서는 메서드의 반환 형식이 제네릭 IEnumerable<T>인지 여부를 확인하는 방법을 보여 줍니다

8. 메서드는 MethodInfo 형식의 인스턴스라고 가정(assume)합니다.


string s = method.ReturnType.GetInterface
    (typeof(System.Collections.Generic.IEnumerable<>).FullName);


public class ExampleClass
{
   public int sampleMember;
   public void SampleMethod() {}

   static void Main()
   {
      Type t = typeof(ExampleClass);
      // Alternatively, you could use
      // ExampleClass obj = new ExampleClass();
      // Type t = obj.GetType();

      Console.WriteLine("Methods:");
      System.Reflection.MethodInfo[] methodInfo = t.GetMethods();

      foreach (System.Reflection.MethodInfo mInfo in methodInfo)
         Console.WriteLine(mInfo.ToString());

      Console.WriteLine("Members:");
      System.Reflection.MemberInfo[] memberInfo = t.GetMembers();

      foreach (System.Reflection.MemberInfo mInfo in memberInfo)
         Console.WriteLine(mInfo.ToString());
   }
}
/*
 Output:
    Methods:
    Void SampleMethod()
    System.String ToString()
    Boolean Equals(System.Object)
    Int32 GetHashCode()
    System.Type GetType()
    Members:
    Void SampleMethod()
    System.String ToString()
    Boolean Equals(System.Object)
    Int32 GetHashCode()
    System.Type GetType()
    Void .ctor()
    Int32 sampleMember
*/


9. 이 샘플에서는 숫자 계산의 결과를 포함하는 데 사용되는 형식을 확인하기 위해 GetType 메서드를 사용합니다.

10. 이 형식은 계산 결과(the resulting number)를 저장하는 데 필요한 요구 사항(requirements)에 따라 달라집니다.


class GetTypeTest
{
    static void Main()
    {
        int radius = 3;
        Console.WriteLine("Area = {0}", radius * radius * Math.PI);
        Console.WriteLine("The type is {0}",
                          (radius * radius * Math.PI).GetType()
        );
    }
}
/*
Output:
Area = 28.2743338823081
The type is System.Double
*/





uint


1. uint 키워드는 다음 표에 표시된 크기와 범위에 따라 값을 저장하는 정수 계열 형식을 나타냅니다.

형식

범위

크기

.NET Framework 형식

uint

0 ~ 4,294,967,295

부호 없는 32비트 정수

System.UInt32

2. uint 형식은 CLS 규격(compliant)이 아닙니다. 

3. 가능하면 int를 사용합니다(use int whenever possible).

4. 다음 예제에서와 같이 uint 형식 변수를 선언하고 초기화할 수 있습니다.


uint myUint = 4294967290;


5. 정수 리터럴에 접미사가 없는 경우 해당 정수 리터럴의 형식은 그 값이 표현될 수 있는 형식인 int, uint, long, ulong 중에서 첫째 형식입니다.

6. 이 예제에서 리터럴 형식은 uint입니다.


uint uInt1 = 123;


7. 또한 다음과 같이 u 또는 U 접미사를 사용할 수 있습니다.


uint uInt2 = 123U;


8. U 또는 u 접미사를 사용하는 경우 리터럴의 형식은 리터럴의 숫자 값에 따라 uint 또는 ulong으로 결정됩니다.


Console.WriteLine(44U.GetType());
Console.WriteLine(323442434344U.GetType());


9. 이 코드는 System.UInt32 뒤에 System.UInt64(followed by)를 표시합니다.

10. 이 두 형식은 각각(respectively) uint 및 ulong의 내부 형식(the underlying types)입니다.

11. 두 번째 리터럴이 너무 커서 uint 형식으로 저장할 수 없기 때문입니다.

12. uint에서 long, ulong, float, double, decimal로의 미리 정의된 암시적 변환이 있습니다.


float myFloat = 4294967290;   // OK: implicit conversion to float


13. byte, ushort, char에서 uint으로의 미리 정의된 암시적 변환이 있습니다.

14. 그 외의 다른 경우에는 캐스트를 사용해야 합니다.

15. 예를 들어 캐스트를 사용하지 않으면 다음 대입문에서 컴파일 오류가 발생합니다.


long aLong = 22;
// Error -- no implicit conversion from long:
uint uInt1 = aLong; 
// OK -- explicit conversion:
uint uInt2 = (uint)aLong;


16. 또한 부동 소수점 형식에서 uint로의 암시적 변환은 없습니다.

17. 예를 들어, 다음 문에서 명시적 캐스트를 사용하지  않으면 컴파일러 오류가 발생합니다.


// Error -- no implicit conversion from double:
uint x = 3.0;
// OK -- explicit conversion:
uint y = (uint)3.0; 


18. 부동 소수점 형식 및 정수 계열 형식이 함께 사용되는 산술식에 대한 자세한 내용은 floatdouble을 참조하십시오.

19. 암시적 숫자 변환 규칙에 대한 자세한 내용은 암시적 숫자 변환 표를 참조하십시오.





ulong


1. ulong 키워드는 다음 표에 표시된 크기와 범위에 따라 값을 저장하는 정수 계열 형식을 나타냅니다.

형식

범위

크기

.NET Framework 형식

ulong

0 ~ 18,446,744,073,709,551,615

부호 없는 64비트 정수

System.UInt64

2. 다음 예제에서와 같이 ulong 변수를 선언하고 초기화할 수 있습니다.


ulong uLong = 9223372036854775808;


3. 정수 리터럴에 접미사가 없는 경우 해당 정수 리터럴의 형식은 그 밧이 표현될 수 있는 형식인 int,,uint, long, ulong 중에서 첫째 형식입니다.

4. 위 예제에서 정수 리터럴 형식은 ulong입니다.

5. 또한 다음 규칙에 따라 리터럴의 형식을 지정하는 접미사를 사용할 수 있습니다.

6. L 또는 l을 사용할 경우 리터럴의 형식은 그 크기에 따라 long 또는 ulong이 됩니다.

System_CAPS_note참고

소문자 "l"도 접미사로 사용할 수 있습니다. 그러나 이 접미사는 숫자 "1"과 쉽게 혼동될 수 있기 때문에 컴파일러 경고가 발생합니다. 혼동을 피하려면 "L"을 사용하는 것이 좋습니다.

7. U 또는 u를 사용할 경우 리터럴의 형식은 그 크기에 따라 uint 또는 ulong이 됩니다.

8. UL, ul, Ul, uL, LU, lu, Lu, lU를 사용할 경우 리터럴의 형식은 ulong이 됩니다.

9. 예를 들어, 다음과 같은 세 개의 문에 대한 출력은 ulong의 별칭에 해당하는 UInt64 시스템 형식이 됩니다.


Console.WriteLine(9223372036854775808L.GetType());
Console.WriteLine(123UL.GetType());
Console.WriteLine((123UL + 456).GetType());


10. 접미사는 오버로드된 메서드를 호출할 때 주로 사용됩니다.

11. 예를 들어 다음과 같이 ulong 및 int 매개 변수를 사용하는 오버로드된 메서드가 있습니다.


public static void SampleMethod(int i) {}
public static void SampleMethod(ulong l) {}


12. 이 경우 ulong 매개 변수와 함께 접미사를 사용하면 올바른 형식이 호출됩니다.


SampleMethod(5);    // Calling the method with the int parameter
SampleMethod(5UL);  // Calling the method with the ulong parameter


13. ulong에서 float, double 또는 decimal로의 암시적 변환이 미리 정의되어 있습니다.

14. ulong에서 다른 정수 계열 형식으로의 암시적 변환은 없습니다.

15. 예를 들어 명시적 캐스트를 사용하지 않으면 다음 문에서 컴파일 오류가 발생합니다.


long long1 = 8UL;   // Error: no implicit conversion from ulong


16. byte, ushort, uint, char에서 ulong으로의 미리 정의된 암시적 변환이 있습니다.

17. 그러나 부동 소수점 형식에서 ulong으로의 암시적 변환은  없습니다.

18. 예를 들어 다음 문에서 명시적 캐스트를 사용하지 않으면 컴파일러 오류가 발생합니다.


// Error -- no implicit conversion from double:
ulong x = 3.0;
// OK -- explicit conversion:
ulong y = (ulong)3.0;  


19. 부동 소수점 형식 및 정수 계열 형식이 함께 사용되는 산술식에 대한 내용은 doublefloat을 참조하십시오.

20. 암시적 숫자 변환 규칙에 대한 자세한 내용은 암시적 숫자 변환 표를 참조하십시오.





unchecked


1. unchecked 키워드는 정수 계열 형식의 산술 연산 및 변환에 대한 오버플로 검사(overflow-checking)를 비활성화(suppress)하는 데 사용됩니다.

2. unchecked 컨텍스트 내에서는 식의 결과 값이 대상 형식(the destination type)의 범위를 벗어나는 경우, 오버플로 플래그가 세워지지 않습니다(the overflow is not flagged).

3. 예를 들어 다음 예제의 계산은 unchecked 블록이나 식의 안쪽에서 수행되므로 결과값이 정수로서는 너무 크다는 사실이 무시되고 int1에 값 -2,147,483,639이 할당됩니다.


unchecked
{
    int1 = 2147483647 + 10;
}
int1 = unchecked(ConstantMax + 10);


4. unchecked 환경을 제거하면 컴파일 오류가 발생합니다.

5. 식의 모든 항(all the terms)이 상수이기 때문에 컴파일 시점에 오버플로를 감지(detect)할 수 있습니다.

6. 비상수 항(non-constant terms)을 포함하는 식은 기본적으로 컴파일 시점과 실행 시점에 검사되지 않습니다.

7. checked 환경을 사용하도록 설정하는 방법에 대한 자세한 내용은 checked를 참조하십시오.

8. 오버플로를 검사하는 작업은 시간이 걸리기 때문에, 오버플로 위험이 없는 경우 unchecked 코드를 사용하면 성능을 향상시킬 수 있습니다.

9. 그러나 오버플로가 발생할 수 있는 경우 checked 환경을 사용해야 합니다.

10. 이 샘플에서는 unchecked 키워드를 사용하는 방법을 보여줍니다.


class UncheckedDemo { static void Main(string[] args) { // int.MaxValue is 2,147,483,647. const int ConstantMax = int.MaxValue; int int1; int int2; int variableMax = 2147483647; // 다음 문은 기본적으로 컴파일 타임에 검사되므로 컴파일되지 않습니다. //int1 = 2147483647 + 10; //int1 = ConstantMax + 10; // int1 에 대입을 컴파일 가능하게 하고 실행하려면 // unchecked 블록이나 식 안에 둡니다. // 다음 문은 컴파일 되고 실행이 됩니다. unchecked { int1 = 2147483647 + 10; } int1 = unchecked(ConstantMax + 10); // 2,147,483,647 과 10 의 합은 -2,147,483,639 로 표시됩니다. Console.WriteLine(int1); // 식이 변수 variableMax 를 포함하므로 기본적으로 컴파일 타임에 검사되지 않습니다. // 그리고 오버플로가 일어나지만 오버플로가 감지되지 않습니다. // 다음 문은 컴파일 되고 실행 됩니다. int2 = variableMax + 10; // 다시, 2,147,483,647 과 10 의 합은 -2,147,483,639 로 표시됩니다. Console.WriteLine(int2); // 런 타임에 int2 에 대입에 대한 오버플로를 검사하려면 // checked 블록이나 식에 선언을 둡니다. // 다음 문은 컴파일 되지만 런 타임에 오버플로 예외가 발생합니다. checked { //int2 = variableMax + 10; } //int2 = checked(variableMax + 10); // Unchecked 섹션은 checked 환경에서 벗어나도록 빈번하게 사용됩니다. // 오버플로 예외가 없을 때 코드의 일부에서 성능 향상을 위해서 입니다. checked { // 오버플로 발생이 있을 수 있다면 checked 환경에서 실행되어야 합니다. unchecked { // 이 섹션은 오버플로가 없다고 확신할 때 // 그리고 성능이 중요할 때 절절합니다. } // 추가 checked 코드 } } }





unsafe


1. unsafe 키워드는 안전하지 않은 컨텍스트를 나타내며, 포인터에 관련된(involving pointers) 모든 작업에 필요합니다.

2. 자세한 내용은 안전하지 않은 코드 및 포인터를 참조하십시오.

3. 형식이나 멤버의 선언에 unsafe 한정자를 사용할 수 있습니다.

4. 따라서 형식이나 멤버의 전체 텍스트 범위(the entire textual extent)가 안전하지 않은 컨텍스트로 취급됩니다.

5. 예를 들어 다음 예제는 unsafe 한정자를 사용해 선언한 메서드입니다.


unsafe static void FastCopy(byte[] src, byte[] dst, int count)
{
    // Unsafe context: can use pointers here.
}


6. 안전하지 않은 컨텍스트의 범위(the scope)는 매개 변수 목록에서 메서드의 끝가지 확장(extend)되므로 매개 변수 목록에 포인터도 사용할 수 있습니다.


unsafe static void FastCopy ( byte* ps, byte* pd, int count ) {...}


7. 또한 안전하지 않은 블록을 사용해 이 블록 내에서 안전하지 않은 코드를 사용할 수도 있습니다.


unsafe
{
    // Unsafe context: can use pointers here.
}


8. 안전하지 않은 코드를 컴파일하려면 컴파일러 옵션 /unsafe를 지정해야 합니다.

9. 안전하지 않은 코드는 공용 언어 런타임으로 확인할 수 없습니다(is not verifiable).


// compile with: /unsafe

class UnsafeTest
{
   // Unsafe method: takes pointer to int:
   unsafe static void SquarePtrParam(int* p)
   {
      *p *= *p;
   }

   unsafe static void Main()
   {
      int i = 5;
      // Unsafe method: uses address-of operator (&):
      SquarePtrParam(&i);
      Console.WriteLine(i);
   }
}
// Output: 25





ushort


1. ushort 키워드는 다음 표에 표시된 크기와 범위에 따라 값을 저장하는 정수 계열 데이터 형식을 나타냅니다.

형식

범위

크기

.NET Framework 형식

ushort

0 ~ 65,535

부호 없는 16비트 정수

System.UInt16

2. 다음 예제와 같이 ushort 변수를 선언하고 초기화할 수 있습니다.


ushort myShort = 65535;


3. 앞의 선언에서 정수 리터럴 65535는 암시적으로 int에서 ushort로 변환됩니다.

4. 정수 리터럴이 ushort 범위를 초과하면 컴파일 오류가 발생합니다.

5. 오버로드된 메서드를 호출할 경우 캐스트를 사용해야 합니다.

6. 예를 들어 다음과 같이 ushort 및 int 매개 변수를 사용하는 오버로드된 메서드가 있습니다.


public static void SampleMethod(int i) {}
public static void SampleMethod(ushort s) {}


7. 이 경우 ushort 캐스트를 사용하면 올바른 형식이 호출됩니다.


// Calls the method with the int parameter:
SampleMethod(5);
// Calls the method with the ushort parameter:
SampleMethod((ushort)5);  


8. ushort에서 int, uint, long, ulong, float, double, decimal로의 미리 정의된 암시적 변환이 있습니다.

9. 또한 byte나 char에서 ushort로의 미리 정의된 암시적 변환이 있습니다.

10. 그 외의 다른 경우에는 캐스트를 사용하여 명시적 변환을 수행해야 합니다.

11. 예를 들어 다음과 같은 두 개의 ushort 변수 x 및 y가 있습니다.


ushort x = 5, y = 12;


12. 다음 할당문의 경우 할당 연산자의 오른쪽에 있는 산술식이 기본적으로 int로 계산되므로 컴파일 오류가 발생합니다.


ushort z = x + y;   // Error: conversion from int to ushort


13. 이 문제를 해결하려면 캐스트를 사용하십시오.


ushort z = (ushort)(x + y); // OK: explicit conversion


14. 대상 변수의 저장소 크기가 같거나 더 클 경우에는 다음과 같은 문을 사용할 수 있습니다.


int m = x + y;
long n = x + y;


15. 또한 부동 소수점 형식에서 ushort로의 암시적 변환은 없습니다.

16. 예를 들어 다음 문에서 명시적 캐스트를 사용하지 않으면 컴파일러 오류가 발생합니다.


// Error -- no implicit conversion from double:
ushort x = 3.0; 
// OK -- explicit conversion:
ushort y = (ushort)3.0;


17. 부동 소수점 형식 및 정수 계열 형식이 함께 사용되는 산술식에 대한 자세한 내용은 floatdouble을 참조하십시오.

18. 암시적 숫자 변환 규칙에 대한 자세한 내용은 암시적 숫자 변환 표를 참조하십시오.





using 지시문(Directive)


1. 네임스페이스의 별칭을 만들거나 다른 네임스페이스에 정의된 형식을 가져올 때(import) 지시문으로 사용할 수 있습니다.

2. using 지시문에는 다음 세 가지 용도(three uses)가 있습니다.

    1) 네임스페이스에서 형식 사용을 한정할(qualify) 필요가 없도록 해당 네임스페이스에서 형식 사용을 허용합니다.


using System.Text;


    2) 형식 이름을 사용하여 액세스를 한정할 필요 없이 형식의 정적 멤버에 액세스하도록 허용합니다.


using static System.Math;


    3) 네임스페이스 또는 형식에 대한 별칭(an alias)을 만듭니다. 이를 using 별칭 지시문이라고 합니다.


using Project = PC.MyCompany.Project;


3. using 키워드는 파일 및 글꼴과 같은 IDisposable 개체가 제대로 처리될 수 있게 도와주는 using 문을 만드는 데도 사용됩니다.

4. 자세한 내용은 using 문을 참조하세요.

5. 형식 이름을 사용하여 액세스를 한정할 필요 없이 형식의 정적 멤버에 액세스할 수 있습니다.


using static System.Console; 
using static System.Math;
class Program 
{ 
    static void Main() 
    { 
        WriteLine(Sqrt(3*3 + 4*4)); 
    } 
}

6. Using static은 액세스 가능한 정적 멤버와 지정된 형식에 선언된 중첩된 형식만 가져옵니다(import).
7. 상속된 멤버(Inherited members)는 가져오지 않습니다.
8. using static 지시문을 사용하여 Visual Basic 모듈을 포함한 모든 명명된 형식에서 가져올 수 있습니다.
9. F# 최상위 함수(top-level functions)가 메타데이터에서 이름이 유효한 C# 식별자인 명명된 형식의 정적 멤버로 나타나면 F# 함수를 가져올 수 있습니다.
10. Using static을 사용하면 지정된 형식에 선언된 확장 메서드를 확장 메서드 조회(extension method lookup에 사용할 수 있습니다.
11. 그러나 확장 메서드의 이름은 코드의 정규화되지 않은 참조에 대한 범위(scope for unqualified reference)로 가져오지 않습니다
12. 같은 컴파일 단위 또는 네임스페이스에서 여러 using static 지시문을 통해 다양한 형식에서 가져온 같은 이름을 사용하는 메서드는 메서드 그룹을 구성합니다.
13. 이들 메서드 그룹 내에서 오버로드 확인(overload resolution)은 일반 C# 규칙(normal C# rules)을 따릅니다.
14. using 지시문의 범위는 지시문이 나타내는 파일로 제한됩니다.
15. using 별칭을 만들면 네임스페이스 또는 형식에 대한 식별자를 더 쉽게 한정할 수 있습니다.
16. using alias 지시문의 오른쪽은 지시문 앞에 나오는 using 지시문과 관계없이 항상 정규화된 형식(a fully-qualified type)이어야 합니다.
17. using 지시문을 만들어서 네임스페이스를 지정할 필요 없이 네임스페이스에서 이 형식을 사용합니다.
18. using 지시문은 지정한 네임스페이스에 중첩된 모든 네임스페이스에 대한 액세스 권한을 제공하지 않습니다.
19. 네임스페이스는 두 가지 범주(two categories)인 사용자 정의 및 시스템 정의로 구분됩니다.
20. 사용자 정의 네임스페이스는 코드에서 정의된 네임스페이스입니다.
21. 시스템 정의 네임스페이스 목록을 보려면 .NET Framework 클래스 라이브러리를 참조하세요.
22. 다른 어셈블리의 메서드를 참조하는 방법에 대한 자세한 내용은 C# DLL 만들기 및 사용을 참조하세요.
23. 다음 예제에서는 using 네임스페이스에 대한 별칭을 정의 및 사용하는 방법을  보여줍니다.

namespace PC
{
    // Define an alias for the nested namespace.
    using Project = PC.MyCompany.Project;
    class A
    {
        void M()
        {
            // Use the alias
            Project.MyClass mc = new Project.MyClass();
        }
    }
    namespace MyCompany
    {
        namespace Project
        {
            public class MyClass { }
        }
    }
}

24. using alias 지시문의 오른쪽에는 공개 제네릭 형식이 포함될 수 없습니다.
25. 예를 들어 List<T>에 대한 using alias를 만들 수 없지만 List<int>에 대한 using alias를 만들 수 있습니다.
26. 다음 예제에서는 클래스에 대한 using 지시문 및 using 별칭을 정의하는 방법을 보여 줍니다.

using System;

// Using alias directive for a class.
using AliasToMyClass = NameSpace1.MyClass;

// Using alias directive for a generic class.
using UsingAlias = NameSpace2.MyClass<int>;

namespace NameSpace1
{
    public class MyClass
    {
        public override string ToString()
        {
            return "You are in NameSpace1.MyClass.";
        }
    }

}

namespace NameSpace2
{
    class MyClass<T>
    {
        public override string ToString()
        {
            return "You are in NameSpace2.MyClass.";
        }
    }
}

namespace NameSpace3
{
    // Using directive:
    using NameSpace1;
    // Using directive:
    using NameSpace2;

    class MainClass
    {
        static void Main()
        {
            AliasToMyClass instance1 = new AliasToMyClass();
            Console.WriteLine(instance1);

            UsingAlias instance2 = new UsingAlias();
            Console.WriteLine(instance2);

        }
    }
}
// Output: 
//    You are in NameSpace1.MyClass.
//    You are in NameSpace2.MyClass.




using 문


1. 개체의 범위를 정의할 때 문으로 사용할 수 있습니다.

2, 개체는 이 범위가 끝날 때 해제됩니다(dispose).

3. IDisposable 개체를 올바르게 사용할 수 있게 해 주는 편리한 구문(a convenient syntax)을 제공합니다.

4. 다음 예제에서는 using 문을 사용하는 방법을 보여 줍니다.


using (Font font1 = new Font("Arial", 10.0f)) 
{
    byte charset = font1.GdiCharSet;
}


5. File 및 Font는 관리되지 않는 리소스(이 경우 파일 핸들 및 장치 컨텍스트)에 액세스하는 관리되는 형식의 예제입니다.

6. 관리되는 형식을 캡슐화하는 관리되지 않는 리소스 및 클래스 라이브러리 형식에는 여러 가지가 있습니다.

7. 이러한 모든 형식은 IDisposable 인터페이스를 구현해야 합니다.

8. 일반적으로(As a rule) IDisposable 개체를 사용할 때는 using 문에서 해당 개체를 선언하고 인스턴스화해야 합니다.

9. using 문은 개체의 Dispose 메서드를 올바른 방법으로 호출하며 앞에서 보여 준 것과 같이 사용할 경우 Dispose가 호출되면 즉시 해당 개체 자체가 범위를 벗어나도록 합니다.

10. using 문은 개체의 메서드를 호출(call methods on the object)하는 동안 예외가 발생하는 경우에도 Dispose가 호출되도록 합니다.

11. try 블록 내에 개체를 배치한 다음 finally 블록에서 Dispose를 호출해도 동일한 결과를 얻을 수 있습니다.

12. 이전의 코드 예제는 컴파일 타임에 다음 코드로 확장됩니다.

13. 중괄호를 추가하면 개체의 제한된 범위가 만들어 집니다.


{
  Font font1 = new Font("Arial", 10.0f);
  try
  {
    byte charset = font1.GdiCharSet;
  }
  finally
  {
    if (font1 != null)
      ((IDisposable)font1).Dispose();
  }
}


14. 다음 예제에서와 같이 형식의 여러 인스턴스(Multiple instances)를 using 문에서 선언할 수 있습니다.

using (Font font3 = new Font("Arial", 10.0f),
            font4 = new Font("Arial", 10.0f))
{
    // Use font3 and font4.
}

15. 리소스 개체를 인스턴스화하고 using 문에 변수를 전달할 수도 있지만 이 방법은 가장 좋은 방법(a best practice)은 아닙니다.
16. 이 경우 관리되지 않는 리소스에 더 이상 액세스할 수 없더라도 제어가 using 블록을 벗어난 후 개체는 범위에 남아 있습니다.
17. 즉(In other words) 개체는 더 이상 완전히 초기화되지 않습니다.
18. using 블록 외부에서 개체를 사용하려고 하면 예외가 throw될 수 있습니다.
19. 이러한 이유로 using 문에서 개체를 인스턴스화하고 해당 범위를 using 블록으로 제한하는 것이 일반적으로 더 좋습니다.

Font font2 = new Font("Arial", 10.0f);
using (font2) // not recommended
{
    // use font2
}
// font2 is still in scope
// but the method call throws an exception
float f = font2.GetHeight(); 




virtual


1. virtual 키워드는 메서드, 속성, 인덱서, 이벤트 선언을 한정(modify)하는 데 사용되며 파생 클래스에서 재정의될 수 있습니다.

2. 예를 들어 다음 메서드는 이 메서드를 상속하는 클래스에 의해 재정의될 수 있습니다.


public virtual double Area() 
{
    return x * y;
}


3. 가상 멤버(a virtual member)의 구현은 파생 클래스의 override 멤버에 의해 변경될 수 있습니다.

4. virtual 키워드를 사용하는 방법에 대한 자세한 내용은 Override 및 New 키워드를 사용하여 버전 관리Override 및 New 키워드를 사용해야 하는 경우를 참조하십시오.

5. 가상 메서드가 호출(invoke)되면 재정의 함수(an overring member)에 대해 개체의 런타임 형식이 검사(check)됩니다.

6. 가장 많이 파생되는 클래스의 재정의 멤버가 호출되므로 멤버가 멤버를 재정의한 파생 클래스가 없을 경우에는 원래 멤버가 호출될 수도 있습니다.

7. 기본적으로 메서드는 비 가상 메서드이며 비 가상 메서드는 재정의될 수 없습니다.

8. virtual 한정자는 static, abstract, private, override 한정자와 함께 사용할 수 없습니다.
9. 다음 예제에서는 가상 속성을 보여줍니다.

class MyBaseClass
{
    // virtual auto-implemented property. Overrides can only
    // provide specialized behavior if they implement get and set accessors.
    public virtual string Name { get; set; }

    // ordinary virtual property with backing field
    private int num;
    public virtual int Number
    {
        get { return num; }
        set { num = value; }
    }
}


class MyDerivedClass : MyBaseClass
{
    private string name;

   // Override auto-implemented property with ordinary property
   // to provide specialized accessor behavior.
    public override string Name
    {
        get
        {
            return name;
        }
        set
        {
            if (value != String.Empty)
            {
                name = value;
            }
            else
            {
                name = "Unknown";
            }
        }
    }

}

10. 가상 속성은 추상 메서드와 비슷하게 작동하지만(behave like) 선언 및 호출 구문에 차이가 있습니다.
    1) 정적 속성에는 virtual 한정자를 사용할 수 없습니다.
    2) 상속된 가상 속성은 override 한정자를 사용하는 속성 선언을 포함하는 방법을  통해 파생 클래스에서 재정의될 수 있습니다.
11. 이 예제에서 Shape 클래스에는 두 개의 좌표 x 및 y와 Area() 가상 메서드가 포함되어 있습니다.
12. 또한 Circle, Cylinder 및 Sphere 등의 서로 다른 형상 클래스가 Shape 클래스를 상속하며 각 도형(each figure)에 대한 표면적(the surface area)이 계산됩니다.
13. 각 파생 클래스는 Area()에 대한 자체적인 재정의 구현을 포함합니다.
14. 상속된 클래스 Circle, Sphere, Cylinder 모두 다음 선언에서와 같이 기본 클래스를 초기화하는 생성자를 사용합니다.

public Cylinder(double r, double h): base(r, h) {}

15. 다음 프로그램은 해당 메서드와 연결된 객체에 따라 적절한 Area() 구현을 호출해서 각 도형에 대한 적절한 면적을 계산하여 표시합니다.

class TestClass
{
    public class Shape
    {
        public const double PI = Math.PI;
        protected double x, y;
        public Shape()
        {
        }
        public Shape(double x, double y)
        {
            this.x = x;
            this.y = y;
        }

        public virtual double Area()
        {
            return x * y;
        }
    }

    public class Circle : Shape
    {
        public Circle(double r) : base(r, 0)
        {
        }

        public override double Area()
        {
            return PI * x * x;
        }
    }

    class Sphere : Shape
    {
        public Sphere(double r) : base(r, 0)
        {
        }

        public override double Area()
        {
            return 4 * PI * x * x;
        }
    }

    class Cylinder : Shape
    {
        public Cylinder(double r, double h) : base(r, h)
        {
        }

        public override double Area()
        {
            return 2 * PI * x * x + 2 * PI * x * y;
        }
    }

    static void Main()
    {
        double r = 3.0, h = 5.0;
        Shape c = new Circle(r);
        Shape s = new Sphere(r);
        Shape l = new Cylinder(r, h);
        // Display results:
        Console.WriteLine("Area of Circle   = {0:F2}", c.Area());
        Console.WriteLine("Area of Sphere   = {0:F2}", s.Area());
        Console.WriteLine("Area of Cylinder = {0:F2}", l.Area());
        }
    }
    /*
        Output:
        Area of Circle   = 28.27
        Area of Sphere   = 113.10
        Area of Cylinder = 150.80
    */




void


1. 메서드에 대한 반환 형식으로 사용하는 경우 void는 메서드가 값을 반환하지 않음을 지정합니다.

2. void 메서드의 매개 변수 목록에 사용할 수 없습니다.

3. 매개 변수가 없으면서 값을 반환하지 않는 메서드는 다음과 같이 선언됩니다.


public void SampleMethod()
{
    // Body of the method.
}


4. 또한 void는 알 수 없는 형식에 대한 포인터를 선언하기 위해 안전하지 않은 컨텍스트에서 사용합니다.

5. 자세한 내용은 포인터 형식을 참조하십시오.

6. void는 .NET Framework System.Void 형식의 별칭입니다.





volatile


1. volatile 키워드는 동시에 실행 중인 여러 스레드에 의해 필드가 수정될 수 있음을 나타냅니다.

2. volatile로 선언된 필드에는 단일 스레드를 통한 액세스를 전제로 하는 컴파일러 최적화가 적용되지 않습니다.

3. 이렇게 하면 필드의 값을 항상 최신 상태로(the most up-to-date) 유지할 수 있습니다.

4. 일반적으로 volatile 한정자는 액세스를 serialize할 때 lock 문을 사용하지 않고 여러 스레드에서 액세스하는 필드에 사용됩니다.

5. volatile 키워드는 다음과 같은 형식의 필드에 적용할 수 있습니다.

    1) 참조 형식

    2) 포인터 형식(unsafe context에서), 포인터 자체는 volatile일 수 있지만 포인터가 가리키는 개체는 volatile일 수 없습니다. 즉(In other words), "volatile 개체에 대한 포인터"를 선언할 수 없습니다.

    3) sbyte, byte, short, ushort, int, uint, char, float 및 bool 같은 형식

    4) 다음과 같은 기본 형식 중 하나를 사용하는 열거형 형식 : byte, sbyte, short, ushort, int, uint

    5) 참조 형식으로 알려진 제네릭 형식 매개 변수

    6) InPtrUIntPtr

6. volatile 키워드는 클래스 또는 구조체의 필드에만 적용할 수 있습니다.

7. 지역 변수는 volatile로 선언할 수 없습니다.

8. 다음 예제에서는 public 필드 변수를 volatile로 선언하는 방법을 보여줍니다.


class VolatileTest
{
    public volatile int i;

    public void Test(int _i)
    {
        i = _i;
    }
}


9. 다음 예제에서는 보조(auxiliary) 또는 작업자(worker) 스레드를 만들고 기본 스레드(the primary)와 함께 이 스레드를 병렬로(in parallel with) 사용하여 작업 처리(processing)를 수행하는 방법을 보여 줍니다.

10. 다중 스레딩에 대한 배경 정보는 Managed Threading스레딩을 참조하십시오.


using System; using System.Threading; public class Worker { // 스레드가 시작되면 이 메서드가 호출됩니다.

public void DoWork() { while (!_shouldStop) { Console.WriteLine("Worker thread: working..."); } Console.WriteLine("Worker thread: terminating gracefully."); } public void RequestStop() { _shouldStop = true; } // 키워드 volatile은 컴파일러에게 이 데이터 멤버는 다중 스레드가 액세스 한다는 것을 알립니다. private volatile bool _shouldStop; } public class WorkerThreadExample { static void Main() { // 작업자 스레드 객체 생성합니다. 스레드가 시작되지는 않습니다. Worker workerObject = new Worker(); Thread workerThread = new Thread(workerObject.DoWork); // 작업자 스레드를 시작합니다. workerThread.Start(); Console.WriteLine("Main thread: starting worker thread..."); // 작업자 스레드가 활성화 될 때까지 루프를 돕니다. while (!workerThread.IsAlive) ; // 작업자 스레드가 어떤 작업을 하도록 주 스레드를 1 밀리 초 동안 sleep 시킵니다. Thread.Sleep(1); // 작업자 스레드가 멈추도록 요청합니다. workerObject.RequestStop(); // Thread.Join 메서드를 사용해서 객체의 스레드가 종료될 때까지 현재 스레드를 중단합니다. workerThread.Join(); Console.WriteLine("Main thread: worker thread has terminated."); } // Sample output: // Main thread: starting worker thread... // Worker thread: working... // Worker thread: working... // Worker thread: working... // Worker thread: working... // Worker thread: working... // Worker thread: working... // Worker thread: terminating gracefully. // Main thread: worker thread has terminated. }





while


1. while 문은 지정된 식이 false가 될 때까지 하나의 문 또는 문 블록을 반복하여 실행합니다.


class WhileTest 
{
    static void Main() 
    {
        int n = 1;
        while (n < 6) 
        {
            Console.WriteLine("Current value of n is {0}", n);
            n++;
        }
    }
}
/*
    Output:
    Current value of n is 1
    Current value of n is 2
    Current value of n is 3
    Current value of n is 4
    Current value of n is 5
 */


class WhileTest2 
{
    static void Main() 
    {
        int n = 1;
        while (n++ < 6) 
        {
            Console.WriteLine("Current value of n is {0}", n);
        }
    }
}
/*
Output:
Current value of n is 2
Current value of n is 3
Current value of n is 4
Current value of n is 5
Current value of n is 6
*/


2. 각 루프를 실행하기 전에 while 식을 테스트하기 때문에 while 루프는 0번 이상(zero or more times) 실행됩니다.

3. 이는 한 번 이상 실행되는 do 루프와 다른 부분입니다.

4. break, goto, return, throw 문이 제어를 루프 밖으로 전달할 때 while 루프를 종료(terminate)할 수 있습니다.

5. 루프를 종료하지 않고 다음 반복(the next iteration) 실행으로 제어를 전달하려면 continue 문을 사용합니다.

6. 위 세 개의 예제에서 출력은 int n이 증가(increment)되는 위치에 따라 달라집니다.

7. 다음 예제에서는 출력이 생성되지 않습니다.


class WhileTest3
{
    static void Main() 
    {
        int n = 5;
        while (++n < 6) 
        {
            Console.WriteLine("Current value of n is {0}", n);
        }
    }
}



 


 


'프로그래밍 > C#' 카테고리의 다른 글

C# 기타  (0) 2016.06.10
C# 컨텍스트 키워드  (0) 2016.06.06
C# 키워드 O~S  (0) 2016.05.31
C# 키워드 F~N  (0) 2016.05.21
C# 키워드 A-E  (0) 2016.05.13
:
Posted by 지훈2