프로그래밍/C#

C# 키워드 A-E

지훈2 2016. 5. 13. 15:23

https://msdn.microsoft.com/ko-kr/library/x53a06bb.aspx

C# 키워드


1. 키워드는 컴파일러에서 특별한 의미를 가지는 미리 정의된 예약 식별자입니다.

2. 키워드의 접두사에 @ 기호가 없으면 프로그램에서 식별자로 사용할 수 없습니다.

3. 예를 들어 @if는 키워드이므로 @if는 올바른 식별자이지만 if는 올바른 식별자가 아닙니다.

4. 이 항목의 첫 번째 표에서는 C# 프로그램의 일부에서 예약 식별자인 키워드를 보여 줍니다.

5. 이 항목의 두 번째 표에서는 C#의 컨텍스트 키워드(the contextual keywords)를 보여 줍니다.

6. 컨텍스트 키워드는 제한된 프로그램 컨텍스트에서만 특별한 의미를 가지므로 컨텍스트 외부에서 식별자로 사용될 수 있습니다.

7. 일반적으로 새 키워드는 C# 언어에 추가되어 이전 버전에서 작성된 프로그램이 중단도지 않도록 컨텍스트 키워드로 추가됩니다.




abstract


1. abstract 한정자(modifier)는 한정되는 것이 구현이 없거나 불완전하다는 것은 나타냅니다(indicate).

2. abstract 한정자는 클래스(class), 메서드(method), 인덱서(indexer), 이벤트(evnet)에 사용할 수 있습니다.

3. 클래스 선언(declaration)에 abstract 한정자를 사용하면 해당 클래스가 다른 클래스의 기본 클래스로만 사용됨을 나타냅니다.

4. abstract로 표시된 멤버나 abstract 클래스에 포함된 멤버는 해당 abstract 클래스에서 파생되는(derive) 클래스에 의해 구현되어야 합니다.

5. 다음 예제에서 Square 클래스는 ShapesClass에서 파생되므로 Area 의 구현을 제공해야 합니다.


abstract class ShapesClass { abstract public int Area(); } class Square : ShapesClass { int side = 0; public Square(int n) { side = n; } // Area 메서드는 컴파일 타임 오류를 피하기 위해 필요합니다. public override int Area() { return side * side; } static void Main() { Square sq = new Square(12); Console.WriteLine("Area of the square = {0}", sq.Area()); } interface I { void M(); } abstract class C : I { public abstract void M(); } } // Output: Area of the square = 144


6. 추상 클래스(Abstract class)는 다음과 같은 특징이 있습니다.

    - 추상 클래스는 인스턴스화할 수 없습니다.

    - 추상 클래스는 추상 메서드와 접근자(accessor)가 포함될 수 있습니다.

    - abstract 한정자와 sealed 한정자는 반대되는 의미(opposite meaning)를 가지므로 추상 클래스를 sealed 한정자로 한정할 수 없습니다.

    - sealed 한정자는 클래스가 상속되는걸 막아주고, abstract 한정자는 클래스가 상속 받는 것이 필요합니다.

    - 추상 클래스에서 파생된 비 추상 클래스는 상속된 모든 추상 메서드 및 접근자의 실제 구현이 포함되어야 합니다.

7. 메서드나 속성 선언에 abstract 한정자를 사용하면 해당 메서드 또는 속성에 구현이 포함되지 않음을 나타냅니다.

8. 추상 메서드는 다음과 같은 특징이 있습니다.

    - 추상 메서드는 암시적으로 가상 메서드(virtual method)입니다.

    - 추상 메서드 선언은 추상 클래스에서만 허용됩니다.

    - 추상 메서드 선언에서는 실제 구현(actual implementation)을 제공하지 않기 때문에 메서드 본문이 없습니다.

    - 메서드 선언은 단순히 세미콜론으로 끝나며, 시그니처 뒤에 중괄호({ })(curly braces)가 없습니다.

public abstract void MyMethod();

    - 구현은 비추상 클래스의 멤버인 재정의 메서드(overrding methodoverride)에 의해 제공됩니다.

    - 추상 메서드 선언에 static 또는 virtual 한정자를 사용하면 오류가 발생합니다.

9. 추상 속성은 추상 메서드와 비슷하게 작동하지만, 선언과 호출 구문(invocation syntax)에 차이가 있습니다.

    - 정적 속성(static property)에는 abstract 한정자를 사용하면 오류가 발생합니다.

    - 상속된 추상 속성은 override 한정자를 사용하는 속성 선언을 포함하는 방법을 통해 파생 클래스에서 재정의(overridden)될 수 있습니다.

10. 추상 클래스에 대한 자세한 정보는 추상 및 봉인(Sealed) 클래스와 클래스 멤버를 참조하십시오.

11. 추상 클래스는 모든 인터페이스 멤버에 대한 구현을 제공해야 합니다.

12. 인터페이스를 구현하는 추상 클래스는 인터페이스 메서드를 추상 클래스에 매핑할 수도 있습니다.

interface I
{
    void M();
}
abstract class C : I
{
    public abstract void M();
}


13. 다음 예제에서 DerivedClass 클래스는 추상 클래스 BaseClass에서 파생되었습니다.

14. 이 추상 클래스에는 추상 메서드 AbstractMethod와 두 개의 추상 속성 X 및 Y가 포함되어 있습니다.

abstract class BaseClass   // 추상 클래스
{
    protected int _x = 100;
    protected int _y = 150;
    public abstract void AbstractMethod();   // 추상 메서드
    public abstract int X    { get; }
    public abstract int Y    { get; }
}

class DerivedClass : BaseClass
{
    public override void AbstractMethod()
    {
        _x++;
        _y++;
    }

    public override int X   // 속성 재정의
    {
        get
        {
            return _x + 10;
        }
    }

    public override int Y   // 속성 재정의
    {
        get
        {
            return _y + 10;
        }
    }

    static void Main()
    {
        DerivedClass o = new DerivedClass();
        o.AbstractMethod();
        Console.WriteLine("x = {0}, y = {1}", o.X, o.Y);
    }
}
// Output: x = 111, y = 161


15. 앞의(preceding) 예제에서 다음과 같은 문으로 추상 클래스를 인스턴스화하려고 하면

BaseClass bc = new BaseClass();   // Error


16. 컴파일러에서 추상 클래스 'BaseClass'의 인스턴스를 만들 수 없다는 오류가 발생합니다.





as


1. 호환되는 참조 형 또는 nullable 형식 사이에서 특정 형식의 변환을 수행할 수 있습니다.

class csrefKeywordsOperators
{
    class Base
    {
        public override string  ToString()
        {
           return "Base";
        }
    }
    class Derived : Base 
    { }

    class Program
    {
        static void Main()
        {

            Derived d = new Derived();

            Base b = d as Base;
            if (b != null)
            {
                Console.WriteLine(b.ToString());
            }

        }
    }
}


2. as는 캐스트 연산과 비슷합니다.

3. 그러나 변환이 불가능한 경우 as는 예외를 일으키는 대신 null을 반환합니다.

expression as type

4. 위의 코드는 한번만 계산된다는것을 제외하고는 다음 식과 동일합니다.

expression is type ? (type)expression : (type)null

5. as 연산자는 참조 변환, nullable 변환, boxing 변환만을 수행합니다.

6. as 연산자는 사용자 정의 변환 같은 다른 변환은 수행할 수 없습니다.

7. 그 대신 캐스트 식을 사용해서 수행해야 합니다.

class ClassA { }
class ClassB { }

class MainClass
{
    static void Main()
    {
        object[] objArray = new object[6];
        objArray[0] = new ClassA();
        objArray[1] = new ClassB();
        objArray[2] = "hello";
        objArray[3] = 123;
        objArray[4] = 123.4;
        objArray[5] = null;

        for (int i = 0; i < objArray.Length; ++i)
        {
            string s = objArray[i] as string;
            Console.Write("{0}:", i);
            if (s != null)
            {
                Console.WriteLine("'" + s + "'");
            }
            else
            {
                Console.WriteLine("not a string");
            }
        }
    }
}
/*
Output:
0:not a string
1:not a string
2:'hello'
3:not a string
4:not a string
5:not a string
*/



 


 


base


1. base 키워드는 파생 클래스에서(from within) 기본 클래스의 멤버에 액세스하는데 사용됩니다.

    - 다른 메서드로 재정의된 기본 클래스의 메서드를 호출합니다.

    - 파생 클래스의 인스턴스를 만들 때 호출되는 기본 클래스 생성자를 지정합니다.

2. 기본 클래스에 액세스하는 것은 생성자 또는 인스턴스 메서드 또는 인스턴스 속성 접근자에서만 가능합니다.

3. 정적(static) 메서드 내에서 base 키워드를 사용할 수 없습니다.

4. 액세스되는 기본 클래스는 클래스 선언에 지정된 기본 클래스입니다.

5. 예를 들어 class ClassB : ClassA 를 지정하면 ClassA의 기본 클래스에 상관없이 ClassB에서 ClassA 멤버에 액세스합니다.

6. 아래 예제에서 기본 클래스인 'Person'과 파생 클래스인 'Employee' 모두에 Getinfo 메서드가 있습니다.

7. base 키워드를 사용하면 파생 클래스에서 기본 클래스의 Getinfo 메소드를 호출할 수 있습니다.


public class Person { protected string ssn = "444-55-6666"; protected string name = "John L. Malgraine"; public virtual void GetInfo() { Console.WriteLine("Name: {0}", name); Console.WriteLine("SSN: {0}", ssn); } } class Employee : Person { public string id = "ABC567EFG"; public override void GetInfo() { // 기본(base) 클래스의 GetInfo 메서드를 호출 base.GetInfo(); Console.WriteLine("Employee ID: {0}", id); } } class TestClass { static void Main() { Employee E = new Employee(); E.GetInfo(); } } /* Output Name: John L. Malgraine SSN: 444-55-6666 Employee ID: ABC567EFG */


8. 아래 예제에서는 파생 클래스의 인스턴스를 만들 때 호출되는 기본(base) 클래스 생성자를 지정하는 방법을 보여줍니다.


public class BaseClass
{
    int num;

    public BaseClass()
    {
        Console.WriteLine("in BaseClass()");
    }

    public BaseClass(int i)
    {
        num = i;
        Console.WriteLine("in BaseClass(int i)");
    }

    public int GetNum()
    {
        return num;
    }
}

public class DerivedClass : BaseClass
{
    // 이 생성자는 BaseClass.BaseClass()를 호출한다.
    public DerivedClass() : base()
    {
    }

    // 이 생성자는 BaseClass.BaseClass(int i) 를 호출한다.
    public DerivedClass(int i) : base(i)
    {
    }

    static void Main()
    {
        DerivedClass md = new DerivedClass();
        DerivedClass md1 = new DerivedClass(1);
    }
}
/*
Output:
in BaseClass()
in BaseClass(int i)
*/



 


 

 

bool

 

1. bool 키워드는 System.Boolean 의 별칭입니다.

2. bool 키워드는 Boolean 값 true와 false를 저장하는 변수를 선언하는 데 사용됩니다.

3. null 값도 가질 수 있는 Boolean 변수가 필요하다면 bool?를 사용하세요.

4. bool 변수에 Boolean 값을 할당할 수 있으며, bool로 계산되는 식을 bool 변수에 할당할 수 있습니다.

 

public class BoolTest { static void Main() { bool b = true; // WriteLine 은 값을 텍스트로 자동변환 합니다.

Console.WriteLine(b); int days = DateTime.Now.DayOfYear; // boolean 식의 결과를 b에 할당합니다.

b = (days % 2 == 0); // b가 true 인지 false 인지에 따라 분기합니다.

if (b) { Console.WriteLine("days is an even number"); } else { Console.WriteLine("days is an odd number"); } } } /* Output: True days is an <even/odd> number */


5. bool 변수의 기본값은 false입니다.

6. bool? 변수의 기본값은 null입니다.

7. C++에서 bool형의 값은 int형의 값으로 변환될 수 있습니다.

8. 즉(in other words), false는 0과 같고, true는 0이 아닌 값과 같습니다.

9. C#에서는 bool형과 다른 형식과의 변환이 없습니다.

10. 예를 들면 다음 if 문은 C#에서 유효하지 않습니다.

 

int x = 123; // if (x) // 오류: "암시적으로 int 형을 bool형으로 변환할 수 없습니다.

{ Console.Write("The value of x is nonzero."); }

 

11. int형의 변수를 테스트하려면 명시적으로 특정 값(예: 0)과 비교해야 합니다.

 

if (x != 0) // C# 의 방식 { Console.Write("The value of x is nonzero."); }


12. 이 예제에서는 키보드로 문자를 입력한 후 입력한 문자가 영문자인지를 검사합니다.

13. 입력한 문자가 영문자이면 대/소문자를 검사합니다.

14. 이러한 검사를 수행하는 데는 IsLetter 및 IsLower가 사용되며 이 둘은 모두 bool 형식을 반환합니다.

 

public class BoolKeyTest
{
    static void Main()
    {
        Console.Write("Enter a character: ");
        char c = (char)Console.Read();
        if (Char.IsLetter(c))
        {
            if (Char.IsLower(c))
            {
                Console.WriteLine("The character is lowercase.");
            }
            else
            {
                Console.WriteLine("The character is uppercase.");
            }
        }
        else
        {
            Console.WriteLine("Not an alphabetic character.");
        }
    }
}
/* Sample Output:
    Enter a character: X
    The character is uppercase.

    Enter a character: x
    The character is lowercase.

    Enter a character: 2
    The character is not an alphabetic character.
 */





break


1. break 문은 가장 가까운 반복문 또는 switch 문을 종료(terminate)합니다.

2. 종료된 문 뒤에 있는 문으로 제어가 전달됩니다.

3. 이 예제에서는 조건문(conditional statement)은 1부터 100까지 세는 카운터가 있지만, break문은 네 번 센 다음 루프를 종료시킵니다. 


class BreakTest { static void Main() { for (int i = 1; i <= 100; i++) { if (i == 5) { break; } Console.WriteLine(i); } // 콘솔을 디버그 모드로 열어 둠 Console.WriteLine("Press any key to exit."); Console.ReadKey(); } } /* Output: 1 2 3 4 */


4. 이 예제에서 break문은 내부 중첩 루프(inner nested loop)를 중단하고 컨트롤을 외부 루프(outer loop)에 반환합니다.


class BreakInNestedLoops { static void Main(string[] args) { int[] numbers = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; char[] letters = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j' }; // 외부 루프 for (int x = 0; x < numbers.Length; x++) { Console.WriteLine("num = {0}", numbers[x]); // 내부 루프 for (int y = 0; y < letters.Length; y++) { if (y == x) { // 컨트롤을 외부 루프에 반환 break; } Console.Write(" {0} ", letters[y]); } Console.WriteLine(); } // 콘솔을 디버그 모드로 열어둠 Console.WriteLine("Press any key to exit."); Console.ReadKey(); } } /* * Output: num = 0 num = 1 a num = 2 a b num = 3 a b c num = 4 a b c d num = 5 a b c d e num = 6 a b c d e f num = 7 a b c d e f g num = 8 a b c d e f g h num = 9 a b c d e f g h i */


5. 이 예제는 switch 문에서 break 사용을 보여줍니다(demonstrate).


class Switch
{
    static void Main()
    {
        Console.Write("Enter your selection (1, 2, or 3): ");
        string s = Console.ReadLine();
        int n = Int32.Parse(s);

        switch (n)
        {
            case 1:
                Console.WriteLine("Current value is {0}", 1);
                break;
            case 2:
                Console.WriteLine("Current value is {0}", 2);
                break;
            case 3:
                Console.WriteLine("Current value is {0}", 3);
                break;
            default:
                Console.WriteLine("Sorry, invalid selection.");
                break;
        }

        // 콘솔을 디버그 모드로 열어 둠
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}
/*
Sample Input: 1

Sample Output:
Enter your selection (1, 2, or 3): 1
Current value is 1
*/


6. 4를 입력하면 다음과 같이 출력됩니다.


Enter your selection (1, 2, or 3): 4
Sorry, invalid selection.





byte


1. byte 키워드는 다음 표에 표시된 대로 값을 저장하는 정수 계열 형식을 나타냅니다(denote).

형식

범위

크기

.NET Framework 형식

byte

0 ~ 255

부호 없는 8비트 정수

System.Byte

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


byte myByte = 255;


3. 앞의 선언(preceding declaration)에서 정수 리터럴 255는 암시적으로 int에서 byte로 변환됩니다.

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

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

6. 저장소 크기가 더 큰 비 리터럴 숫자 형식은 암시적으로 byte로 변환할 수 없습니다.

7. 정수 계열 형식의 저장소 크기에 대한 자세한 내용은 정수 계열 형식 표를 참조하십시오.

형식

범위

크기

sbyte

-128 ~ 127

부호 있는 8비트 정수

byte

0 ~ 255

부호 없는 8비트 정수

char

U+0000 ~ U+ffff

유니코드 16비트 문자

short

-32,768 ~ 32,767

부호 있는 16비트 정수

ushort

0 ~ 65,535

부호 없는 16비트 정수

int

-2,147,483,648 ~ 2,147,483,647

부호 있는 32비트 정수

uint

0 ~ 4,294,967,295

부호 없는 32비트 정수

long

-9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807

부호 있는 64비트 정수

ulong

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

부호 없는 64비트 정수

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


byte x = 10, y = 20;


9. 다음 대입 문(assignment statement)의 경우 컴파일 오류가 발생합니다.

10. 왜냐하면 대입 연산자의 오른쪽에 있는 산술식(arithmetic expression)이 기본적으로 int로 계산되기 때문입니다.


// 오류: int에서 byte로 변환: byte z = x + y;


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


// OK: 명시적 변환: byte z = (byte)(x + y);


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


int x = 10, y = 20;
int m = x + y;
long n = x + y;


13. 부동 소수점 형식(floating-point types)에서 byte로의 암시적 변환은 없습니다.

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


// 오류: double로부터의 암시적 변환은 없음: byte x = 3.0; // OK: 명시적 변환: byte y = (byte)3.0;


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

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


public static void SampleMethod(int i) {}
public static void SampleMethod(byte b) {}


17. byte 캐스트를 사용하면 올바른 형식이 호출 됩니다.


// int 파라미터로 메서드 호출: SampleMethod(5); // byte 파라미터로 메서드 호출: SampleMethod((byte)5);


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

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





case


1. switch 문은 후보 목록에서 실행할 스위치 섹션을 선택하는 제어문입니다.

2. switch 문에는 스위치 섹션이 하나 이상 포함됩니다.

3. 각 switch 섹션에는 하나 이상의 레이블 및 하나 이상의 문이 있습니다.

4. 다음 예제에서는 세 개의 스위치 섹션이 있는 간단한 switch 문을 보여줍니다.

5. 각 스위치 섹션에는 case 1과 같은 하나의 case 레이블과 두 개의 문이 있습니다.


int caseSwitch = 1;
switch (caseSwitch)
{
    case 1:
        Console.WriteLine("Case 1");
        break;
    case 2:
        Console.WriteLine("Case 2");
        break;
    default:
        Console.WriteLine("Default case");
        break;
}


6. 각 case 레이블은 상수 값을 지정합니다.

7. switch 문은 case 레이블과 switch 식의 값(위의 예제에서 caseSwitch)이 일치하는 스위치 섹션으로 제어를 보냅니다.

8. case 레이블이 일치하는 값이 없다면, 제어는 default 센션으로 보내집니다(transferred).

9. default 섹션이 없다면, 어떠한 작업도 수행되지 않으며, 제어는 switch 문 외부로 보내집니다.

10. 이번 예제에서는 case 1 이 caseSwitch 값과 일치하기 때문에 첫 번째 스위치 섹션의 문이 실행됩니다.

11. switch 문은 스위치 섹션의 수에는 제한이 없으며, 각 섹션에는 하나 이상의 case 레이블을 포함할 수 있습니다.(아래 예제의 문자열 case 레이블 참조)

12. 하지만, 두 case 레이블에 동일한 상수 값을 포함할 수는 없습니다.

14. 선택한 스위치 섹션에서 문 목록의 실행은 첫 번째 문으로 시작하고 일반적으로 break, goto case, return, throw 같은 점프문에 도달할 때까지 문 목록 전체를 진행합니다.

15. 이 경우 제어는 switch 문 외부로 또는 또 다른 case 레이블로 넘어갑니다.

16. C++과 달리, C#은 한 스위치 섹션에서 다음 스위치 섹션으로 실행을 계속하는 것을 허용하지 않습니다.

17. 다음 코드는 오류를 발생시킵니다.


switch (caseSwitch) { // 다음 스위치 섹션은 에러를 발생시킵니다. case 1: Console.WriteLine("Case 1..."); // break나 다른 점프문을 추가하세요. case 2: Console.WriteLine("... and/or Case 2"); break; }


18. C#은 요구사항에 따라 마지막 섹션을 포함한 스위치 섹션의 끝에 도달할 수 없어야 합니다.

19. 즉, 다른 언어와는 달리 다음 스위치 섹션으로 진행하지 않습니다.

20. 이 요구사항(requirement)은 보통 break 문을 사용하여 충족할 수 있지만, 다음 case 는 유효합니다.

21. 왜냐하면 문 목록의 끝이 도달될 수 없기 때문입니다.


case 4:
    while (true)
        Console.WriteLine("Endless looping. . . .");


22. 다음 예제에서는 switch 문의 요구사항과 기능(capabilities)을 보여줍니다.


class Program { static void Main(string[] args) { int switchExpression = 3; switch (switchExpression) { // 스위치 섹션은 한 개 이상의 case 레이블을 가질 수 있다. case 0: case 1: Console.WriteLine("Case 0 or 1"); // 대부분의 switch 섹션은 점프문을 가집니다. // 예를 들면, break, goto, return 입니다. // 문 목록의 끝은 도달할 수 없어야 합니다. break; case 2: Console.WriteLine("Case 2"); break; // 다음 라인은 warning이 발생합니다. Console.WriteLine("Unreachable code"); // 다음 라인의 7 - 4 는 3으로 계산됩니다. case 7 - 4: Console.WriteLine("Case 3"); break; // switchExpression의 값이 0, 1, 2, 3이 아니라면 // default case 가 실행됩니다. default: Console.WriteLine("Default case (optional)"); // 마지막 섹션을 포함해서 다음 스위치 섹션으로 진행되지 않습니다. break; } } }


23. 마지막 예제에서는 문자열 변수 str 및 문자열 case 레이블이 실행 흐름을 제어합니다.


class SwitchTest { static void Main() { Console.WriteLine("Coffee sizes: 1=small 2=medium 3=large"); Console.Write("Please enter your selection: "); string str = Console.ReadLine(); int cost = 0; // case 2와 3의 goto 문을 주의하세요. // 기본 비용 25 센트가 medium과 large 사이즈의 추가 비용에 더해집니다. switch (str) { case "1": case "small": cost += 25; break; case "2": case "medium": cost += 25; goto case "1"; case "3": case "large": cost += 50; goto case "1"; default: Console.WriteLine("Invalid selection. Please select 1, 2, or 3."); break; } if (cost != 0) { Console.WriteLine("Please insert {0} cents.", cost); } Console.WriteLine("Thank you for your business."); } } /* Sample Input: 2 Sample Output: Coffee sizes: 1=small 2=medium 3=large Please enter your selection: 2 Please insert 50 cents. Thank you for your business. */






try-catch


1. try-catch 문은 try 블록에 이어 서로 다른 예외에 대한 처리기(handler)를 지정하는 하나 이상의 catch 절로 구성됩니다.

2. 예외가 throw되면 CLR(common language runtime)에서는 이 예외를 처리하는 catch 문을 검색합니다.

3. 현재 실행중인 메서드에 catch 블록이 포함되지 않으면, CLR에서는 현재 메서드를 호출한 메서드 등에서 호출 스택까지 확인합니다.

4. catch 블록을 찾을 수 없으면, CLR에서는 처리되지 않은 예외 메시지(unhandled exception message)를 사용자에게 표시하고 프로그램의 예외를 중지합니다

5. try 블록에는 예외를 가져올 수 있는 보호된 코드(guarded code)가 포합됩니다.

6. 블록은 예외가 throw되거나 성공적으로 완료될 때까지 실행됩니다.

7. 예를 들어, null 객체를 캐스팅하는 다음 시도에서 NullReferenceException 예외가 발생합니다.


object o2 = null;
try
{
    int i2 = (int)o2;   // Error
}


8. catch 절은 예외 형식을 catch하는 인수 없이 사용할 수 있지만 이 사용은 권장되지 않습니다.

9. 일반적으로(In general), 복구하는 방법을 아는 예외만 catch해야 합니다.

10. 따라서(Therefore), 항상 System.Exception에서 파생된 객체 인수를 지정해야 합니다.


catch (InvalidCastException e) 
{
}


11. 같은 try-catch 문에서 특정(specific) catch 절을 두 개 이상 사용할 수 있습니다.

12. 이 경우(In this case), catch 절의 순서는 중요합니다.

13. 왜냐하면 catch 절은 순서대로(in order) 검사되기(examined) 때문입니다.

14. 더 구체적인(more specific) 예외를 덜 구체적인(less specific) 예외보다 먼저 catch합니다.

15. 나중에 나타나는 블록에 도달할 수 없도록 catch 블록 순서를 지정하면 컴파일러에서 오류가 발생합니다.

16. catch 인수를 사용하여 처리할 예외를 필터링할 수 있습니다.

17. 예외를 추가로 검사하는 조건자(predicate) 식을 사용하여 예외를 처리할지 결정할 수도 있습니다.

18. 조건자 식에서 false를 반환하면 처리기(handler) 검색이 계속됩니다.


Catch (ArgumentException e) if (e.ParamName == “…”)
{
}


19. 필터 덕분에 스택이 손상되지 않으므로 예외 필터는 catch하고 다시 throw하는 것이 좋습니다.

20. 나중에 나타나는 처리기(handler)가 스택을 덤프하면, 예외가 다시 throw된 마지막 위치가 아니라 예외가 원래 발생한 위치를 확인할 수 있습니다.

21. 예외 필터 식의 일반적인 사용법은 로깅입니다.

22. 로그에도 출력되는 항상 false를 반환하는 조건자 함수를 만들 수 있고, 예외를 처리하고 rethrow 할 필요 없이 진행되는 대로 예외를 기록할 수 있습니다.

23. throw 문을 catch 블록에서 사용하여 catch 문에 의해 catch된 에외를 다시 throw할 수 있습니다.

24. 다음 에제에서는 IOException 예외에서 소스 정보를 추출하고 예외를 부모 메서드에 throw합니다.


catch (FileNotFoundException e)
{
    // FileNotFoundExceptions 예외가 여기서 처리된다.
}
catch (IOException e)
{
    // 이 예외로부터 정보를 추출한 다음
    // 부모 메서드에 throw한다.
    if (e.Source != null)
        Console.WriteLine("IOException source: {0}", e.Source);
    throw;
}


25. 하나의 예외를 catch하고 다른 예외를 throw할 수 있습니다.

26. 이 작업을 할 때, 다음 예제에서처럼 내부 예외로 catch 한 예외를 지정합니다.


catch (InvalidCastException e) { // 여기에서 작업을 수행하고, 새로운 예외를 throw 합니다. throw new YourCustomException("Put your error message here.", e); }


27. 다음 예제와 같이 지정된 조건이 true이면 예외를 다시 throw할 수도 있습니다.


catch (InvalidCastException e)
{
    if (e.Data == null)
    {
        throw;
    }
    else
    {
        // Take some action.
    }
 }


28. try 블록 내부에서 선언된 변수만 초기화하세요.(therein: 그 안에)

29. 그렇지 않으면(otherwise), 블록의 실행이 완료되기 전에 예외가 발생할 수 있습니다.

30. 예를 들어 다음 코드 예제에서 변수 n은 try 블록 내부에서 초기화됩니다.

31. try 블록 외부에서 Write(n) 문의 n 변수를 사용하려는 시도가 컴파일 오류를 발생시킵니다.


static void Main() { int n; try { // 이 변수를 여기에서 초기화하지 마세요. n = 123; } catch { } // 오류: 할당되지 않은 지역 변수의 사용 'n' Console.Write(n); }



32. catch에 대한 자세한 내용은 try-catch-finally 를 참조하세요.


비동기 메서드의 예외

1. 비동기 메서드(async method)는 async 한정자를 통해 표시되고, 대개 하나 이상의 await 식 및 문을 포합합니다.

2. await 식은 await 연산자를 Task 또는 Task<TResult>에 적용합니다.

3. 컨트롤이 async 메서드의 await에 도달하면 대기중인(awaited) 작업이 완료될 때까지 메서드의 진행이 중단됩니다.

4. 자세한 내용은 Async 및 Await를 사용한 비동기 프로그램비동기 프로그램의 제어 흐름을 참조하세요.

5. await가 적용되는 완료된 작업은 오류 상태(faulted state)에 있을 수 있습니다.

6. 왜냐하면 작업을 반환하는 메서드 안에서 처리되지 않은(unhandled) 예외 때문입니다.

7. 작업을 기다리면 예외가 throw됩니다.

8. 작업을 반환하는 비동기 프로세스가 취소되면 작업이 취소됨 상태로 종료될 수 있습니다.

9. 취소된 작업을 기다리면 OperationCanceledException이 throw됩니다.

10. 비동기 프로세스를 취소하는 방법에 대한 자세한 내용은 Async 응용 프로그램 미세 조정을 참조하세요.

11. 예외를 catch하려면 try 블록에서 작업을 기다리고 연결된(associated) catch 블록에서 예외를 catch하세요.

12. 대기 중인 async 메서드에서 여러 예외가 발생했기 때문에 작업이 오류 상태에 있을 수 있습니다.

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

14. 작업을 기다릴 때 예외 중 하나만 catch되고 catch될 예외를 예상할 수 없습니다.

15. 다음 예제에서, try 블록에는 예외를 가져올 수 있는 ProcessString 메서드의 호출이 포함되어 있습니다.

16. catch 절에는 화면에 메시지만 표시하는 예외 처리기가 포함됩니다.

17. throw 문이 myMethod 내부에서 호출되면, 시스템에서는 catch 문을 검색하고 Exception caught 메시지를 표시합니다.


class TryFinallyTest
{
    static void ProcessString(string s)
    {
        if (s == null)
        {
            throw new ArgumentNullException();
        }
    }

    static void Main()
    {
        string s = null; // For demonstration purposes.

        try
        {            
            ProcessString(s);
        }

        catch (Exception e)
        {
            Console.WriteLine("{0} Exception caught.", e);
        }
    }
}
    /*
    Output:
    System.ArgumentNullException: Value cannot be null.
       at TryFinallyTest.Main() Exception caught.
     * */

18. 다음 에제에서는 두 catch 블록이 사용되고 먼저 나오는 가장 구체적인(specific) 예외가 catch됩니다.

19. 가장 덜 구체적인 예외(the least specific exception)를 catch하려면 ProcessString의 throw 문을 throw new Exception() 문으로 바꿔야 합니다.

20. 가장 덜 구체적인 catch 블록을 예제에 첫 번째로 배치하면 다음 오류 메시지가 표시됩니다. "A previous catch clause already catches all exceptions of this or a super type ("System.Exception")."


class ThrowTest3
{
    static void ProcessString(string s)
    {
        if (s == null)
        {
            throw new ArgumentNullException();
        }
    }

    static void Main()
    {
        try
        {
            string s = null;
            ProcessString(s);
        }
        // 가장 구체적인:
        catch (ArgumentNullException e)
        {
            Console.WriteLine("{0} First exception caught.", e);
        }
        // 가장 덜 구체적인:
        catch (Exception e)
        {
            Console.WriteLine("{0} Second exception caught.", e);
        }
    }
}
/*
 Output:
 System.ArgumentNullException: Value cannot be null.
 at Test.ThrowTest3.ProcessString(String s) ... First exception caught.
*/


21. 다음 예제에서는 async 메서드 처리에 대한 예외 처리를 보여줍니다(illustrate).

22. async 작업이 throw 하는 예외를 catch하려면, try 블록에 await 식을 배치하고, catch 블록에서 예외를 catch합니다.

23. 예제에서 throw new Exception 줄의 주석 처리를 제거(uncomment)하여 예외 처리를 보여 줍니다.

24. 작업의 IsFaulted 속성이 True로 설정되고, 작업의 Exception.InnerException 속성이 예외로 설정되고, 예외가 catch 블록에서 catch됩니다.

25. throw new OperationCancelledException 줄의 주석 처리를 제거하여 비동기 프로세스를 취소할 수 있을 때 발생하는 동작을 보여 줍니다.

26. 작업의 IsCanceled 속성이 true로 설정되고, 예외가 catch 블록에서 catch됩니다.

27. 이 예제에 적용되지 않는 몇몇 조건에서는 작업의 IsFaulted 속성이 true로 설정되고 IsCanceled가 false로 설정됩니다.


public async Task DoSomethingAsync() { Task<string> theTask = DelayAsync(); try { string result = await theTask; Debug.WriteLine("Result: " + result); } catch (Exception ex) { Debug.WriteLine("Exception Message: " + ex.Message); } Debug.WriteLine("Task IsCanceled: " + theTask.IsCanceled); Debug.WriteLine("Task IsFaulted: " + theTask.IsFaulted); if (theTask.Exception != null) { Debug.WriteLine("Task Exception Message: " + theTask.Exception.Message); Debug.WriteLine("Task Inner Exception Message: " + theTask.Exception.InnerException.Message); } } private async Task<string> DelayAsync() { await Task.Delay(100); // 다음 라인의 각각의 주석 처리를 제거하여 에러 처리를 확인해 보세요. //throw new OperationCanceledException("canceled"); //throw new Exception("Something happened."); return "Done"; } // 대기 중(awaited)인 메서드에서 예외가 throw 되지 않을 때 출력 내용 // Result: Done // Task IsCanceled: False // Task IsFaulted: False // 대기 중인 메서드에서 예외가 throw 될때의 출력 내용 // Exception Message: Something happened. // Task IsCanceled: False // Task IsFaulted: True // Task Exception Message: One or more errors occurred. // Task Inner Exception Message: Something happened. // 대기 중인 메서드에서 OperationCanceledException 또는 TaskCanceledException 예외가 throw 될 때의 출력 내용 // Exception Message: canceled // Task IsCanceled: True // Task IsFaulted: False


28. 다음 예제에서는 여러 예외가 발생할 수 있는 경우 예외 처리(exception handling)를 보여 줍니다.

29. try 블록은 Task.WhenAll에 대한 호출에서 반환된 작업을 기다립니다.

30. WhenAll이 적용된 세 개의 작업이 완료되면 작업이 완료됩니다.

31. 세 작업에서 각각 예외가 발생합니다.

32. catch 블록은 Task.WhenAll에서 반환된 작업의 Exception.InnerExceptions 속성에 있는 예외를 반복합니다(iterate)


public async Task DoMultipleAsync()
{
    Task theTask1 = ExcAsync(info: "First Task");
    Task theTask2 = ExcAsync(info: "Second Task");
    Task theTask3 = ExcAsync(info: "Third Task");

    Task allTasks = Task.WhenAll(theTask1, theTask2, theTask3);

    try
    {
        await allTasks;
    }
    catch (Exception ex)
    {
        Debug.WriteLine("Exception: " + ex.Message);
        Debug.WriteLine("Task IsFaulted: " + allTasks.IsFaulted);
        foreach (var inEx in allTasks.Exception.InnerExceptions)
        {
            Debug.WriteLine("Task Inner Exception: " + inEx.Message);
        }
    }
}

private async Task ExcAsync(string info)
{
    await Task.Delay(100);

    throw new Exception("Error-" + info);
}

// Output:
//   Exception: Error-First Task
//   Task IsFaulted: True
//   Task Inner Exception: Error-First Task
//   Task Inner Exception: Error-Second Task
//   Task Inner Exception: Error-Third Task





char


1. char 키워드는 System.Char 구조체의 인스턴스를 선언하기위해 사용됩니다.

2. .NET 프레임워크는 유니코드 문자를 표현하기 위해 System.char 구조체를 사용합니다.

3. Char 객체의 값은 16비트 숫자 (서수) 값입니다.

4. 유니코드 문자(Unicode characters)는 대부분의 전세계 언어를 나타내는 데 사용됩니다.

형식

범위

크기

.NET Framework 형식

char

U + 0000 ~ U + FFFF

유니코드 16비트 문자

System::Char

5. char 형식의 상수(constant)는 문자 리터럴, 16진수 이스케이프 시퀀스(hexadecimal escape sequence), 유니코드 표현(Unicode representation)

6. 또한 정수 계열 문자 코드를 변환(cast)할 수 있습니다.


char[] chars = new char[4];

chars[0] = 'X';        // 문자 리터럴 (Character literal)
chars[1] = '\x0058';   // 16진수 (Hexadecimal)
chars[2] = (char)88;   // 정수 계열로부터 변환 (Cast from integral type)
chars[3] = '\u0058';   // 유니코드 (Unicode)

foreach (char c in chars)
{
    Console.Write(c + " ");
}
// Output: X X X X


7. char 형식은 ushort, int, uint, long, ulong, float, double로 암시적으로 변환할 수 있습니다.

8. 그러나 다른 형식에서 char 형식으로의 암시적 변환은 없습니다.

9. System.Char 형식은 char 값 처리에 사용할 수 있는 몇 가지 정적 메서드(several static methods)를 제공합니다.





class


1. 클래스는 다음 예제와 같이 class 키워드를 사용하여 선언합니다.


class TestClass
{
    // Methods, properties, fields, events, delegates 
    // and nested classes go here.
}


2. C#에서 단일 상속(single inheritance)만 허용됩니다.

3. 즉, 클래스는 하나의 기본 클래스에서만 구현(implementation)을 상속(inherit)할 수 있습니다.

4. 그러나, 클래스는 한 개 이상의 인터페이스를 구현할 수 있습니다.

5. 다음 표에는 클래스 상속과 인터페이스 구현을 보여줍니다.

상속

예제

없음

class ClassA { }

Single

class DerivedClass: BaseClass { }

없음, 두 개의 인터페이스 구현

class ImplClass: IFace1, IFace2 { }

단일, 한 개의 인터페이스 구현

class ImplDerivedClass: BaseClass, IFace1 { }

6. 다른 클래스 안에서 중첩이 아닌 네임스페이스 안에서 직접 선언하는 클래스는 public이거나 internal일 수 있습니다.

7. 클래스는 기본적으로(by default) internal입니다.

8. 중첩된 클래스(nested classes)를 포함해서 클래스 멤버는 public, protected, protected, internal, private 일 수 있습니다.

9. 멤버는 기본적으로 private 입니다.

10. 자세한 내용은 액세스 한정자를 참조하십시오.

11. 형식 매개변수(type parameters)가 있는 제네릭 클래스(generic classes)를 선언할 수 있습니다.

12. 자세한 내용은 제네릭 클래스를 참조하십시오.

13. 클래스는 다음과 같은 멤버들의 선언이 포함될 수 있습니다.


14. 다음 예제에서는 클래스 필드, 생성자, 메서드 선언을 보여줍니다.

15. 또한 개체를 인스턴스화(instantiation)하는 것과 인스턴스 데이터를 출력하는 것을 보여줍니다.

16. 이 예제에서는 두 개의 클래스를 선언합니다.

17. 첫째 클래스인 Child 클래스에는 두 개의 private 필드(name과 age)와 두 개의 public 메서드가 있습니다.

18. 두 번째 클래스인 StringTest는 Main을 포함하는 데 사용됩니다.


class Child
{
    private int age;
    private string name;

    // 기본 생성자:
    public Child()
    {
        name = "N/A";
    }

    // 생성자:
    public Child(string name, int age)
    {
        this.name = name;
        this.age = age;
    }

    // 출력 메서드:
    public void PrintChild()
    {
        Console.WriteLine("{0}, {1} years old.", name, age);
    }
}

class StringTest
{
    static void Main()
    {
        // new 연산자를 사용해서 객체 생성
        Child child1 = new Child("Craig", 11);
        Child child2 = new Child("Sally", 10);

        // 기본 생성자를 사용해서 객체 생성
        Child child3 = new Child();

        // 결과 표시
        Console.Write("Child #1: ");
        child1.PrintChild();
        Console.Write("Child #2: ");
        child2.PrintChild();
        Console.Write("Child #3: ");
        child3.PrintChild();
    }
}
/* Output:
    Child #1: Craig, 11 years old.
    Child #2: Sally, 10 years old.
    Child #3: N/A, 0 years old.
*/


19. 앞의 예제(preceding example)에서 private 필드(name과 age)는 Child 클래스의 public 메서드를 통해서만 액세스할 수 있습니다.

20. 예를 들어 다음과 같은 문을 사용하면 Main 메서드에서 자식의 이름을 출력할 수 없습니다.


Console.Write(child1.name); // 오류


21. Main에서 Child의 private 멤버에 액세스하려면 Main이 이 클래스의 멤버여야 합니다.

22. 액세스 한정자가 없다면 기본값으로 private입니다.

23. 그래서 이 예제에서 private 키워드가 제거되더라도 데이터 멤버는 여전히 private입니다.

24. 마지막으로, 기본 생성자(child3)을 사용해서 생성된 객체에서, age 필드는 기본적으로 0으로 초기화됩니다.





const


1. 상수 필드(constant field) 또는 지역 상수(constant local)를 선언할 때는 const 키워드를 사용합니다.

2. 상수 필드 및 지역 상수는 변수가 아니며 수정할 수 없습니다.

3. 상수는 숫자, bool, 문자열, null 참조일 수 있습니다.

4. 언제든지(at any time) 변경될 수 있는 정보를 나타낼 때는 상수를 만들지 마세요.

5. 예를 들어, 상수 필드를 사용하여 서비스의 가격, 제품 버전 번호 또는 회사의 브랜드 이름을 저장하지 마세요.

6. 이러한 값은 시간이 지남에 따라(over time) 변경될 수 있으며, 컴파일러는 상수를 전파하므로(propagate) 변경 내용을 보기 위해서는 라이브러리를 사용하여 컴파일된 다른 코드를 다시 컴파일해야 합니다.

7. readonly 키워드도 참조하세요.


const int x = 0;
public const double gravitationalConstant = 6.673e-11;
private const string productName = "Visual C#";


8. 상수 선언의 형식은 선언에서 제공하는 멤버의 형식을 지정합니다.

9. 지역 상수 또는 상수 필드의 이니셜라이저는 대상 형식으로 암시적으로 변환될 수 있는 상수 식이어야 합니다.

10. 상수 식은 컴파일 타임에 완전히 계산될 수 있는 식입니다.

11. 따라서(Therefore), 참조 형식의 상수에 대해 가능한 것은 string 및 null 참조뿐입니다.

12. 상수 선언에서는 다음과 같이 여러 상수를 선언할 수 있습니다.


public const double x = 1.0, y = 2.0, z = 3.0;


13. static 한정자는 상수 선언에는 허용되지 않습니다.

14. 상수는 다음과 같이 상수 식에 참여할 수 있습니다.


public const int c1 = 5;
public const int c2 = c1 + 100;


System_CAPS_note참고

1. readonly 키워드는 const 키워드와 다릅니다. const 필드는 필드 선언에서만 초기화될 수 있습니다.

2. readonly 필드는 선언이나 생성자에서 초기화될 수 있습니다.

3. 따라서 readonly 필드는 사용된 생성자에 따라 다른 값을 가질 수 있습니다. 또한 const 필드가 컴파일 타임 상수라고 하더라도 readonly 필드는 다음 줄에서와 같이 런타임 상수에 사용될 수 있습니다.

public static readonly uint l1 = (uint)DateTime.Now.Ticks;

public class ConstTest 
{
    class SampleClass 
    {
        public int x;
        public int y;
        public const int c1 = 5;
        public const int c2 = c1 + 5;

        public SampleClass(int p1, int p2) 
        {
            x = p1; 
            y = p2;
        }
    }

    static void Main() 
    {
        SampleClass mC = new SampleClass(11, 22);   
        Console.WriteLine("x = {0}, y = {1}", mC.x, mC.y);
        Console.WriteLine("c1 = {0}, c2 = {1}", 
                          SampleClass.c1, SampleClass.c2 );
    }
}
/* Output
    x = 11, y = 22
    c1 = 5, c2 = 10
 */


15. 이 예제에서는 상수를 로컬 변수로 사용하는 방법을 보여 줍니다.


public class SealedTest
{
    static void Main()
    {
        const int c = 707;
        Console.WriteLine("My local constant = {0}", c);
    }
}
// Output: My local constant = 707





continue


1. continue 문은 while, do, for, foreach 의 제어를 다음 반복으로 전달합니다.

2. 이 예제에서, 카운터는 1에서 10까지 세도록 초기화 됩니다.

3. 식 (i < 9)과 함께 continue 문을 사용하여 continue와 for 본문의 끝 사이가 스킵됩니다.


class ContinueTest
{
    static void Main()
    {
        for (int i = 1; i <= 10; i++)
        {
            if (i < 9)
            {
                continue;
            }
            Console.WriteLine(i);
        }

        // Keep the console open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}
/*
Output:
9
10
*/





decimal


1. decimal 키워드는 128비트 데이터 형식을 나타냅니다.

2. decimal 형식은 부동 소수점 형식(floating-point types)에 비해 전체 자릿수(precision)는 크고, 범위는 작아서 재무(financial) 및 통화(monetary) 계산에 적합합니다.

3. 다음 표에서는 decimal 형식의 대략적인 범위와 전체 자릿수를 보여 줍니다.

형식

근사 범위

전체 자릿수 (Precision)

.NET Framework 형식

decimal

(-7.9 x 1028 - 7.9 x 1028) / (100 - 28)

28-29개의 유효 자릿수

System::Decimal

4. 숫자 형식의 실수 리터럴(numeric real literal)이 decimal로 처리(treated)되게 하려면, 다음과 같이 접미사(suffix) m 또는 M을 사용합니다.


decimal myMoney = 300.5m;


5. 접미사 m이 없으면 숫자가 double로 처리되어 컴파일 오류가 발생합니다.

6. 정수 계열 형식은 암시적으로 decimal로 변환되어 계산 결과가 decimal로 나타납니다.

7. 따라서 접미사를 붙이지 않고 decimal 변수를 초기화할 수 있습니다.


decimal myMoney = 300;


8. 부동 소수점 형식과 decimal 형식 간의 암시적 변환은 없습니다.

9. 따라서, 이 두 형식 간의 변환에는 캐스트(cast)를 사용해야 합니다.


decimal myMoney = 99.9m;
double x = (double)myMoney;
myMoney = (decimal)x;


10. 같은 식에서 decimal과 숫자 정수 계열 형식(numeric integral types)을 혼합(mix)할 수 있습니다.

11. 그러나 캐스트를 사용하지 않고 decimal과 부동 소수점 형식을 혼합하면 컴파일 오류가 발생합니다.

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

13. 명시적 숫자 변환에 대한 자세한 내용은 명시적 숫자 변환 표를 참조하십시오.

14. String.Format 메서드를 사용하거나 String.Format()을 호출하는 Console.Write 메서드를 통해 결과의 서식을 지정할 수 있습니다.

15. 통화(currency) 서식은 이 문서 뒷부분에 있는 두 번째 예제처럼 표준 통화 서식 문자열 "C" 또는 "c"를 사용하여 지정합니다.

16. String.Format 메서드에 대한 자세한 내용은 String.Format을 참조하십시오.

17. 다음은 double 및 decimal 변수를 추가하려고 시도하여 컴파일러 오류가 발생하는 예제입니다.


double dub = 9; // 다음 라인은 다음과 같은 오류를 발생시킵니다. // "연산자 '+' 는 'double' 형식과 'decimal'의 피연산자에 적용될 수 없습니다."

Console.WriteLine(dec + dub); // 둘 중 하나에 명시적 캐스트를 사용해서 오류를 고칠 수 있습니다. Console.WriteLine(dec + (decimal)dub); Console.WriteLine((double)dec + dub);


18. 다음 예제에서는 같은 식에 decimal과 int가 혼합되어 있습니다. 계산 결과는 decimal type입니다.


public class TestDecimal { static void Main() { decimal d = 9.1m; int y = 3; Console.WriteLine(d + y); // 결과가 decimal로 변환됨 } } // Output: 12.1


19. 다음 예제에서는, 통화 서식 문자열(currency format string)을 사용하여 출력 서식을 지정합니다.

20. x는 소수 자릿수(decimal places)가 $0.99를 초과하기 때문에 반올림됩니다(rounded).

21. 최대 자릿수(maximum exact digits)를 나타내는 변수 y는 올바른 서식(correct format)으로 정확하게 표시됩니다.


public class TestDecimalFormat
{
    static void Main()
    {
        decimal x = 0.999m;
        decimal y = 9999999999999999999999999999m;
        Console.WriteLine("My amount = {0:C}", x);
        Console.WriteLine("Your amount = {0:C}", y);
    }
}
/* Output:
    My amount = $1.00
    Your amount = $9,999,999,999,999,999,999,999,999,999.00
*/





제네릭 코드의 default 키워드


1. 제네릭 클래스 및 메서드에서 다음과 같은 내용을 미리 알지 못하는 경우 매개 변수화된 형식 T에 기본값을 할당하는 방법에 대한 문제가 발생합니다.

    - T가 참조 형식인지 값 형식인지 여부

    - T가 값 형식인 경우 숫자 값인지 구조체인지 여부

2. t가 매개변수화된 형식 T의 변수인 경우 "t = null"과 같은 구문은 T가 참조형식인 경우에만 유효하고,

3. "t = 0"은 구조체가 아닌 숫자 값 형식인 경우에만 사용할 수 있습니다.

4. 참조 형식에 대해서는 null을 반환하고 숫자 값 형식에는 0을 반환하는 default 키워드를 사용하면 이 문제를 해결할 수 있습니다.

5. 구조체에 대해서는 멤버가 값 형식인지 참조 형식인지 여부에 따라 0 또는 null로 초기화된 구조체의 각 멤버가 반환됩니다.

6. nullable 값 형식의 경우 default는 다른 구조체와 같이 초기화되는 System.Nullable<T>을 반환합니다.

7. GenericList<T> 클래스에 있는  다음 에제에서는 default 키워드를 사용하는 방법을 보여줍니다.

8. 자세한 내용은 제네릭 개요(Generics Overview)를 참조하십시오.


namespace ConsoleApplication1 { class Program { static void Main(string[] args) { // 정수형의 비어있지 않은 리스트로 테스트합니다. GenericList<int> gll = new GenericList<int>(); gll.AddNode(5); gll.AddNode(4); gll.AddNode(3); int intVal = gll.GetLast(); // 다음 라인은 5를 출력합니다. System.Console.WriteLine(intVal); // 정수형의 빈 리스트로 테스트합니다. GenericList<int> gll2 = new GenericList<int>(); intVal = gll2.GetLast(); // 다음 라인은 0을 출력합니다. System.Console.WriteLine(intVal); // 문자열의 비어있지 않은 리스트로 테스트합니다. GenericList<string> gll3 = new GenericList<string>(); gll3.AddNode("five"); gll3.AddNode("four"); string sVal = gll3.GetLast(); // 다음 라인은 five를 출력합니다. System.Console.WriteLine(sVal); // 문자열의 비어있는 리스트로 테스트합니다. GenericList<string> gll4 = new GenericList<string>(); sVal = gll4.GetLast(); // 다음 라인은 빈 줄을 출력합니다. System.Console.WriteLine(sVal); } } // T 는 GenericList의 특정한 인스턴스에 저장된 데이터 형식입니다. public class GenericList<T> { private class Node { // 각 노드는 리스트에서 다음 노드로의 참조를 가집니다. public Node Next; // 각 노드는 T 형식의 값을 가집니다. public T Data; } // 리스트는 처음에는 빈 값입니다. private Node head = null; // 데이터 값으로 t를 가지는 리스트의 처음에 노드를 추가합니다. public void AddNode(T t) { Node newNode = new Node(); newNode.Next = head; newNode.Data = t; head = newNode; } // 다음 메서드는 리스트의 마지막 노드에 저장된 데이터 값을 반환합니다. // 만약 리스트가 비었다면 T 형식의 default 값이 반환됩니다. public T GetLast() { // 메서드의 값으로 temp의 값이 반환됩니다. // 다음 선언은 temp를 적당한 T 형식의 default 값으로 초기화합니다. // 리스트 목록이 비어있다면 default 값이 반환됩니다. T temp = default(T); Node current = head; while (current != null) { temp = current.Data; current = current.Next; } return temp; } } }





delegate


1. 대리자(delegate) 형식의 선언은 메서드 시그니처(signature)와 비슷하므로, 반환 값을 가지며 모든 유형의 매개 변수를 원하는 수만큼 사용할 수 있습니다.


public delegate void TestDelegate(string message);
public delegate int TestDelegate(MyType m, long num);


2. delegate는 명명된 메서드나 익명 메서드를 캡슐화(encapsulate)하는 데 사용할 수 있는 참조 형식입니다.

3. 대리자는 C++의 함수 포인터와 비슷하지만, 대리자는 형식 안전성(type-safe)과 보안성(secure)을 제공한다는 점이 다릅니다.

4. 대리자 응용 프로그램에 대한 자세한 내용은 대리자제네릭 대리자를 참조하십시오.

5. 대리자는 이벤트의 기반을 형성합니다.

6. 대리자는 명명된 메서드나 무명 메서드와 연결하여(associate) 인스턴스화할 수 있습니다.

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

8. 대리자는 호환되는 반환 형식과 입력 매개 변수가 있는 메서드나 람다 식으로 인스턴스화해야 합니다.

9. 메서드 시그니처에 허용되는 변동(variance) 범위에 대한 자세한 내용은 대리자의 가변성을 참조하십시오.

10. 무명메서드와 함께 사용하는 경우, 무명 메서드와 연결되는 대리자와 코드는 함께 선언됩니다.

11. 이 단원에서는 대리자를 인스턴스화하는 두 가지 방법을 모두 설명합니다.


// 대리자 선언 -- 필요한 시그니처 정의: delegate double MathAction(double num); class DelegateTest { // 시그니처와 일치하는 Regular 메서드: static double Double(double input) { return input * 2; } static void Main() { // 명명된 메서드로 대리자 인스턴스화: MathAction ma = Double; // 대리자 ma 호출: double multByTwo = ma(4.5); Console.WriteLine("multByTwo: {0}", multByTwo); // 무명 메서드로 대리자 인스턴스화: MathAction ma2 = delegate(double input) { return input * input; }; double square = ma2(5); Console.WriteLine("square: {0}", square); // 람다 식으로 대리자 인스턴스화: MathAction ma3 = s => s * s * s; double cube = ma3(4.375); Console.WriteLine("cube: {0}", cube); } // Output: // multByTwo: 9 // square: 25 // cube: 83.740234375 }





do


1. do 문은 지정된 식이 false가 될 때까지 하나의 문 또는 문의 블록을 반복하여(repeatedly) 실행합니다.

2. 문의 본문은 단일 문으로 구성되지 않는한 중괄호({})로 묶여야 합니다.

3. 이 경우 중괄호는 선택 사항입니다.

4. 다음 에제에서, do-while 루프 문은 변수 x가 5보다 작은 동안에만 실행합니다.


public class TestDoWhile 
{
    public static void Main () 
    {
        int x = 0;
        do 
        {
            Console.WriteLine(x);
            x++;
        } while (x < 5);
    }
}
/*
    Output:
    0
    1
    2
    3
    4
*/


5. while 루프는 while 문과 달리 조건식이 계산되기 전에 한 번(one time) 실행됩니다.

6. do-while 블록 내의 모든 위치에서(at any point) break 문을 사용하여 루프를 벗어날 수(break out of) 있습니다.

7. continue 문을 사용하여 while 식 계산 문으로 직접 보낼 수(step directly) 있습니다.

8. while 식이 true이면, 루프의 첫 번째 문에서 실행이 계속됩니다.

9. 식이 false이면 do-while 루프 당ㅁ의 첫 번째 문에서 실행이 계속됩니다.

10. do-while 루프는 goto, return, throw 문을 사용하여 종료할(exited) 수도 있습니다.


double


1. double 키워드는 64비트 부동 소수점 값(64-bit floating-point values)을 저장하는 단순 형식을 나타냅니다(signify).

2. 다음 표에서는 double 형식의 전체 자릿수(precision)와 근사 범위(approximate range)를 보여 줍니다.


형식

근사 범위

전체 자릿수 (Precision)

.NET Framework 형식

double

±5.0 × 10−324 ~ ±1.7 × 10308

15-16개의 자릿수

System::Double

3. 기본적으로 할당 연산자(assignment operator)의 오른쪽에 있는 실수형 숫자 리터럴은 double로 처리됩니다.

4. 그러나 정수형 숫자를 double로 처리하려면 다음 예제와 같이 d 또는 D 접미사를 사용하십시오.


double x = 3D;


5. 한 식에서 숫자 정수 형식(numeric integral types)과 부동 소수점 형식을 함께 사용할 수 있습니다.

6. 이 경우, 정수 형식은 부동 소수점 형식으로 변환됩니다.

7. 식의 계산은 다음 규칙에 따라 수행됩니다.

    - 부동 소수점 형식 중 하나가 double인 경우 식은 double로 계산되고, 관계식(relational expressions) 또는 Boolean식의 경우에는 bool로 계산됩니다.

    - 식에 double형이 없는 경우 식은 float으로 계산되고, Boolean식 또는 관계식의 경우에는 bool로 계산됩니다.

8. 부동 소수점 식에는 다음과 같은 값이 포함될 수 있습니다.

    - 양수 및 음수 0

    - 양수(positive) 및 음수(negative) 무한(infinity)

    - NAN(Not-a-Number) 값

    - 0이 아닌 값의 유한 집합(finite set)

9. 이러한 값에 대한 자세한 내용은 IEEE 웹 사이트에서 IEEE Standard for Binary Floating-Point Arithmetic을 참조하십시오.

10. 다음 예제에서는 int, short, float, double 키워드가 함께 추가되고 결과는 double 입니다.


// 식에서 형식 혼합 class MixedTypes { static void Main() { int x = 3; float y = 4.5f; short z = 5; double w = 1.7E+3; // 두번째 인자의 결과는 double이다. Console.WriteLine("The sum is {0}", x + y + z + w); } } // Output: The sum is 1712.5





if-else


1. if 문은 Boolean 식의 값에 따라 실행한 문을 식별합니다(identify).

2. 다음 예제에서는 Boolean 변수 result 가 true로 설정된 다음 if 무에서 확인됩니다(checked).

3. 출력(output)은 The condition is true입니다.


bool condition = true;

if (condition)
{
    Console.WriteLine("The variable is set to true.");
}
else
{
    Console.WriteLine("The variable is set to false.");
}


4. 콘솔 앱의 Main 메서드에 배치하여 이 항목의 예제를 실행할 수 있습니다.

5. C#에서 if 문은 다음 예제와 같이 두 가지 형식을 사용할 수 있습니다.


// if-else 문

if (condition)

{

then-statement;

}

else

{

else-statement;

}

// Next statement in the program.


// else 없는 if 문

if (condition)

{

then-statement;

}

// Next statement in the program.


6. if-else 문에서 condition이 true로 평가되는 경우, then-statement가 실행됩니다.

7. condition이 false이면 else-statement가 실행됩니다.

8. condition이 true인 동시에(simultaneously) false일 수는 없으므로, then-statement 및 else-statement를 둘 다 실행할 수는 없습니다. 

9. then-statement 또는 else-statement가 실행된 후 제어가 if 문 뒤의 다음 문으로 전송됩니다(transferred).

10. if else 문을 포함하지 않는 if 문에서 condition이 true이면 then-statement가 실행됩니다.

11. condition이 false이면 제어가 if 문 뒤의 다음 문으로 전송됩니다.

12. then-statement 및 else-statement는 둘 다 단일 문이나 중괄호({})로 묶인(enclosed) 여러 문으로 구성될 수 있습니다.

13. 단일 문의 경우, 중괄호(braces)는 선택 사항(optional)이지만 권장됩니다(recommended).

14. then-statement 및 else-statement의 문은 원래 if 문 내부에 중첩된(nested) 다른 if 문을 포함하여 모든 종류(of any kind)일 수 있습니다.

15. 중첩된 if 문에서 각 else 절은 해당 else가 없는 마지막 if에 속합니다.

16. 다음 예제에서 m > 10 및 n > 20이 둘 다 true이면 Result1이 나타납니다(appear).

17. m > 10이 true이지만 n > 20이 false이면 Result2가 나타납니다.


// m = 12 로 해 본 다음, m = 8로 해보라. int m = 12; int n = 18; if (m > 10) if (n > 20) { Console.WriteLine("Result1"); } else { Console.WriteLine("Result2"); }


18. (m > 10)이 false일 때 Result2를 대신 표시하려는 경우 다음 예제와 같이 중괄호로 중첩된 if 문의 시작 및 끝을 설정하여 해당 연결(association)을 지정할 수 있습니다.

// m = 12로 해 본 다음, m = 8로 해보라. if (m > 10) { if (n > 20) Console.WriteLine("Result1"); } else { Console.WriteLine("Result2"); }


19. 조건 (m > 10)이 false이면 Result2가 나타납니다.

20. 다음 예제에서는, 키보드에서 문자(character) 하나를 입력하며, 프로그램이 중첩된 if 문을 사용하여 입력 문자가 영문자(alphabetic character)인지 여부를 확인합니다.

21. 입력 문자가 영문자이면 프로그램은 입력 문자가 소문자(lowercase)인지 대문자(uppercase)인지 확인(check)합니다.

22. 각 경우에 대한 메시지가 나타납니다.(A message appears for each case.)


Console.Write("Enter a character: ");
char c = (char)Console.Read();
if (Char.IsLetter(c))
{
    if (Char.IsLower(c))
    {
        Console.WriteLine("The character is lowercase.");
    }
    else
    {
        Console.WriteLine("The character is uppercase.");
    }
}
else
{
    Console.WriteLine("The character isn't an alphabetic character.");
}

//Sample Output:

//Enter a character: 2
//The character isn't an alphabetic character.

//Enter a character: A
//The character is uppercase.

//Enter a character: h
//The character is lowercase.


23. 다음 부분 코드(partial code)와 같이 if 문을 else 블록 안에 중첩할 수도 있습니다.

24. 예제에서는 if 문을 else 블록 2개와 then 블록 1개 안에 중첩합니다.

25. 주석은 각 블록에서 true 또는 false인 조건을 지정합니다.


// 이 변수들의 값을 변경해서 값들을 확인해보세요.
bool Condition1 = true;
bool Condition2 = true;
bool Condition3 = true;
bool Condition4 = true;

if (Condition1)
{
    // Condition1 is true.
}
else if (Condition2)
{
    // Condition1 is false and Condition2 is true.
}
else if (Condition3)
{
    if (Condition4)
    {
        // Condition1 and Condition2 are false. Condition3 and Condition4 are true.
    }
    else
    {
        // Condition1, Condition2, and Condition4 are false. Condition3 is true.
    }
}
else
{
    // Condition1, Condition2, and Condition3 are false.


26. 다음 에제는 입력 문자가 소문자, 대문자, 또는 숫자인지를 확인합니다(determine).

27. 세 가지 조건이 모두 false이면 문자는 영숫자 문자(alphanumeric character)가 아닙니다.

28. 예제에서는 각 경우에 대한 메시지가 표시됩니다.


Console.Write("Enter a character: ");
char ch = (char)Console.Read();

if (Char.IsUpper(ch))
{
    Console.WriteLine("The character is an uppercase letter.");
}
else if (Char.IsLower(ch))
{
    Console.WriteLine("The character is a lowercase letter.");
}
else if (Char.IsDigit(ch))
{
    Console.WriteLine("The character is a number.");
}
else
{
    Console.WriteLine("The character is not alphanumeric.");
}

//Sample Input and Output:
//Enter a character: E
//The character is an uppercase letter.

//Enter a character: e
//The character is a lowercase letter.

//Enter a character: 4
//The character is a number.

//Enter a character: =
//The character is not alphanumeric.


29. else 블록 또는 then 블록의 문이 유효한 모든 문일 수 있는 것과 마찬가지로, 유효한 Boolean 식을 조건에 대해 사용할 수 있습니다.

30. &&, &, ||, |, !와 같은 논리 연산자를 사용하여 복합(compound) 조건을 만들 수 있습니다.

31. 다음 코드는 예제를 보여 줍니다.


// NOT bool result = true; if (!result) {

Console.WriteLine("The condition is true (result is false).");

} else

{

Console.WriteLine("The condition is false (result is true).");

} // Short-circuit AND

int m = 9;

int n = 7;

int p = 5;

if (m >= n && m >= p) {     Console.WriteLine("Nothing is larger than m.");

} // AND and NOT

if (m >= n && !(p > m)) {     Console.WriteLine("Nothing is larger than m.");

// Short-circuit OR

if (m > n || m > p) {

Console.WriteLine("m isn't the smallest.");

}

// NOT and OR 

m = 4;

if (!(m >= n || m >= p))

{

Console.WriteLine("Now m is the smallest.");

// Output:

// The condition is false (result is true).

// Nothing is larger than m. 

// Nothing is larger than m. 

// m isn't the smallest. 

// Now m is the smallest.





enum


1. enum 키워드는 열거자 목록(enumerator list)이라고 하는 명명된 상수 집합으로 구성된 고유 형식(distinct type)인 열거형을 선언하는데 사용됩니다.

2. 대개(usually) 네임스페이스의 모든 클래스가 같은 수준으로 열거형에 액세스할 수 있도록 네임스페이스 내에서 직접 열거형을 정의하는 것이 좋습니다.

3. 기본적으로 첫 번째 열거자 값은 0이며, 그 이후(successive)의 열거자 값은 순서대로 1씩 증가됩니다.

4. 예를 들어 다음 열거형에서 Sat은 0, Sun은 1, Mon은 2 등입니다.


enum Days {Sat, Sun, Mon, Tue, Wed, Thu, Fri};


5. 다음 예제와 같이 열거자(enumerator)는 이니셜라이저(initializers)를 사용하여 기본값을 재정의(override)할 수 있습니다.


enum Days {Sat=1, Sun, Mon, Tue, Wed, Thu, Fri};


6. 위의 열거형에서 요소의 순서는 0대신 1부터 시작합니다.

7. 그러나 값이 0인 상수를 포함하는 것이 좋습니다.

8. 자세한 내용은 열거형 형식(Enumeration Types)을 참조하세요.

9. 모든 열거형에는 기본(underlying) 형식이 있으며, 해당 형식은 char 형식을 제외한 임의의 정수 계열 형식이 될 수 있습니다. 열거형 요소의 기본적인 기본 형식(default underlying type)은 int입니다.

10. byte와 같은 다른 정수 형식의 열거형을 선언하려면, 다음 예제에서와 같이 콜론을 사용하여 식별자 다음에 형식을 사용합니다.


// 키워드(keyword) 식별자(identifier) : 형식(type) {열거자(enumerator), ..} enum Days : byte {Sat=1, Sun, Mon, Tue, Wed, Thu, Fri};


11. 열거형을 승인된(approved) 형식은 byte, sbyte, short, int, uint, long, ulong 입니다.

12. Days 형식의 변수에는 명명된 상수뿐 아니라 기본 형식의 범위에 있는 모든 값을 할당할 수 있습니다.

13. enum E의 기본값은 식 (E)0으로 계산된(produced) 값입니다.

System_CAPS_note참고

열거자의 이름에는 공백이 포함될 수 없습니다.

14. 기본 형식(underlying)은 각 열거자에 할당될 저장소 크기를 지정합니다.

15. 그러나 enum 형식에서 정수 계열 형식으로 변환하려면 명시적 캐스트가 필요합니다.

16. 예를 들어 다음 문은 enum을 int로 변환하는 캐스트를 사용하여 열거자 Sun을 int 형식 변수에 대입합니다.


int x = (int)Days.Sun;


17. 비트(bitwise) OR 연산으로 결합될 수 있는 열거형(enumeration)에 System.FlagsAttribute를 적용하면 일부 도구에서 이 열거형을 사용할 때 해당 특성(attribute)이 enum의 동작(behavior)에 영향(affect)을 줍니다.

18. Console 클래스 메소드 및 식 계산기(Evaluator) 등의 도구를 사용할 때 이러한 변경 사항(changes)을 확인할 수 있습니다.

19. 세번째 예제를 참조하세요.

20;. 다른 상수와 마찬가지로 컴파일 타임에 열거형의 개별(individual) 값에 대한 모든 참조는 숫자 리터럴로 변환됩니다.

21. 따라서 상수에서 설명하는대로 잠재적인 버전 문제(potential versioning issues)가 발생할 수 있습니다.

22. 새 버전의 열거형에 값을 추가로 할당하거나 새 버전의 열거형 멤버 값을 변경하면 종속된(dependent) 소스 코드에 문제가 발생할 수 있습니다.

23. switch 문에서 열거형 값이 사용되는 경우가 많습니다.

24. enum 형식에 요소가 추가되었으면 switch 문의 기본 섹션을 예기치 않게 선택할 수 있습니다.

25. 다른 개발자가 코드를 사용하 경우 enum 형식에 새 요소가 추가된다면 해당 코드에서 이를 적절히 처리할 수 있도록 지침(guidelines)을 제공해야 합니다..

26. 다음 예제에서는 열거형 Days를 선언합니다.

27. 두 개의 열거자를 명시적으로 정수로 변환하여 정수 변수에 대입합니다.


public class EnumTest
{
    enum Days { Sun, Mon, Tue, Wed, Thu, Fri, Sat };

    static void Main()
    {
        int x = (int)Days.Sun;
        int y = (int)Days.Fri;
        Console.WriteLine("Sun = {0}", x);
        Console.WriteLine("Fri = {0}", y);
    }
}
/* Output:
   Sun = 0
   Fri = 5
*/


28. 다음 예제에서는 base-type 옵션을 사용하여 멤버가 long 형식인 enum을 선언합니다.

29. 열거형(enumeration)의 기본 형식이 long인 경우에도 캐스트를 사용하여 열거형 멤버를 long 형식으로 명시적으로 변환해야 합니다.


public class EnumTest2
{
    enum Range : long { Max = 2147483648L, Min = 255L };
    static void Main()
    {
        long x = (long)Range.Max;
        long y = (long)Range.Min;
        Console.WriteLine("Max = {0}", x);
        Console.WriteLine("Min = {0}", y);
    }
}
/* Output:
   Max = 2147483648
   Min = 255
*/


30. 다음 코드 에제에서는 enum 선언에 System.FlagsAttribute 특성을 사용하는 방법과 그 결과(effect)를 보여 줍니다.


// Flags 또는 FlagsAttribute 속성을 추가하세요. [Flags] public enum CarOptions { // SunRoof의 flag는 0001입니다. SunRoof = 0x01, // Spoiler의 flag는 0010입니다. Spoiler = 0x02, // FogLights의 flag는 0100입니다. FogLights = 0x04, // TintedWindows의 flag는 1000입니다. TintedWindows = 0x08, } class FlagTest { static void Main() { // 0001과 0100의 비트 OR은 0101입니다.. CarOptions options = CarOptions.SunRoof | CarOptions.FogLights; // Flags 속성이 지정되었기 때문에 Console.WriteLine 는 // 변수 options 에서 1의 값을 가지는 flag 에 대한 각 enum 요소의 이름을 표시합니다. Console.WriteLine(options); // 0101의 정수 값은 5입니다. Console.WriteLine((int)options); } } /* Output: SunRoof, FogLights 5 */


31. Flags를 제거하면 예에 다음 값이 표시됩니다.

5

5





event


1. event 키워드는 게시자 클래스(publisher class)에서 이벤트를 선언하는 데 사용합니다.

2. 다음 에제에서는 EventHandler를 내부(underlying) 대리자 형식으로 사용하는 이벤트를 선언하고 발생(raise)시키는 방법을 보여 줍니다.

3. 제네릭 EventHandler<TEventArgs> 대리자 형식을 사용하는 방법과 이벤트를 구독하고 이벤트 처리기 메서드를 만드는 방법도 보여 주는 전체 코드 예제는 방법: .NET Framework 지침을 따르는 게시를 참조하십시오.


public class SampleEventArgs { public SampleEventArgs(string s) { Text = s; } public String Text {get; private set;} // readonly } public class Publisher { // 대리자 선언 (비 제네릭 패턴을 사용한다면). public delegate void SampleEventHandler(object sender, SampleEventArgs e); // 이벤트 선언. public event SampleEventHandler SampleEvent; // 파생된 클래스에서 이벤트 발생을 가능하게 하도록 하기 위해서

// protected virtual method 메서드 안에서 해당 이벤트를 작성합니다. protected virtual void RaiseSampleEvent() { // () 연산자를 사용해서 이벤트를 발생시킵니다.. if (SampleEvent != null) SampleEvent(this, new SampleEventArgs("Hello")); } }


4. 이벤트는 해당 이벤트가 선언된 클래스나 구조체(publisher class)에서만 호출할 수 있는 특수한 종류의 멀티캐스트 대리자입니다.

5. 다른 클래스나 구조체가 이벤트를 구독할 경우, 해당 이벤트 핸들러 메서드는 게시자 클래스에서 이벤트를 발생시킬 때 호출됩니다.

6. 자세한 내용 및 코드 예제를 보려면 이벤트대리자를 참조하십시오.

7. 이벤트는 public, private, protected, protectedinternal로 표시할 수 있습니다.

8. 이러한 액세스 한정자는 클래스 사용자가 이벤트에 액세스하는 방식을 정의합니다.

9. 자세한 내용은 액세스 한정자를 참조하십시오.


키워드

설명

자세한 내용

static

클래스의 인스턴스가 없어도 언제든지 호출자가 이벤트를 사용할 수 있습니다.

정적 클래스 및 정적 클래스 멤버(C# 프로그래밍 가이드)

virtual

파생 클래스에서 override 키워드를 사용하여 이벤트 동작을 재정의할 수 있습니다.

상속(C# 프로그래밍 가이드)

sealed

파생 클래스에 대해 더 이상 virtual이 아님을 지정합니다.

 

abstract

컴파일러에서는 add 및 remove 이벤트 접근자 블록을 생성하지 않으므로 파생 클래스에서 고유한 구현을 제공해야 합니다.

 

10. static 키워드를 사용하면 이벤트를 정적 이벤트로 선언할 수 있습니다.

11. 이렇게 하면 클래스의 인스턴스가 없어도 언제든지(at any time) 호출자가 이벤트를 사용할 수 있습니다.

12. 자세한 내용은 정적 클래스 및 정적 클래스 멤버를 참조하십시오.

13. virtual 키워드를 사용하면 이벤트를 가상(virtual) 이벤트로 표시할 수 있습니다.

14. 이렇게 하면 파생 클래스에서 override 키워드를 사용하여 이벤트 동작(behavior)을 재정의할 수 있습니다.

15. 자세한 내용은 상속을 참조하십시오.

16. virtual 이벤트를 재정의하는 이벤트는 sealed 이벤트가 될 수도 있습니다. 이렇게 하면 파생 클래스에 대해 이 이벤트가 virtual event가 아닌 것으로 지정됩니다.

17. 마지막으로(Lastly) 이벤트는 abstract로 선언할 수 있습니다. 이렇게 하면 컴파일러에서 add 및 remove 이벤트 접근자 블록이 생성되지 않습니다.

18. 따라서(Therefore) 파생 클래스에서 자체 구현(their own implementation)해야 합니다.





explicit


1. explicit 키워드는 캐스트를 통해 호출해야 할 사용자 정의 형식 변환 연산자를 선언합니다.

2. 예를 들어, 다음 연산자는 Fahrenheit라는 클래스를 Celsius라는 클래스로 변환합니다.


// Fahrenheit라는 클래스 안에서 정의되어야 합니다. public static explicit operator Celsius(Fahrenheit fahr) { return new Celsius((5.0f / 9.0f) * (fahr.degrees - 32)); }


3. 이 변환 연산자는 다음과 같이 호출할 수 있습니다.


Fahrenheit fahr = new Fahrenheit(100.0f);
Console.Write("{0} Fahrenheit", fahr.Degrees);
Celsius c = (Celsius)fahr;


4. 변환 연산자는 소스 형식에서 대상 형식으로 변환합니다.

5. 소스 형식은 변환 연산자를 제공합니다.

6. 암시적(implicit) 변환과 달리 명식적(explicit) 변환은 캐스트를 통해 호출해야 합니다.

7. 변환 연산으로 예외가 발생하거나 정보가 손실될 수 있는 경우 변환 연산을 explicit로 표시해야 합니다.

8. 이렇게 해야 컴파일러가 예상치 않은 결과(unforeseen consequences)의 변환 연산을 호출하지 않습니다.

9. 캐스트를 생락하면(omit) 컴파일 타임 오류 CS0266이 발생합니다(result in).

10. 자세한 내용은 변환 연산자 사용을 참조하십시오.

11. 다음 에제에서는 Fahrenheit 및 Celsius 클래스를 제공합니다.

12. 각 클래스는 다른 클래스에 대한 명시적 변환 연산자를 제공합니다.


class Celsius { public Celsius(float temp) { degrees = temp; } public static explicit operator Fahrenheit(Celsius c) { return new Fahrenheit((9.0f / 5.0f) * c.degrees + 32); } public float Degrees { get { return degrees; } } private float degrees; } class Fahrenheit { public Fahrenheit(float temp) { degrees = temp; } // Fahrenheit라는 클래스 내부에서 정의되어야 합니다. public static explicit operator Celsius(Fahrenheit fahr) { return new Celsius((5.0f / 9.0f) * (fahr.degrees - 32)); } public float Degrees { get { return degrees; } } private float degrees; } class MainClass { static void Main() { Fahrenheit fahr = new Fahrenheit(100.0f); Console.Write("{0} Fahrenheit", fahr.Degrees); Celsius c = (Celsius)fahr; Console.Write(" = {0} Celsius", c.Degrees); Fahrenheit fahr2 = (Fahrenheit)c; Console.WriteLine(" = {0} Fahrenheit", fahr2.Degrees); } } // Output: // 100 Fahrenheit = 37.77778 Celsius = 100 Fahrenheit


13. 다음 예제에서는 단일 10 진수(single decimal digit)를 나타내는 Digit 구조체를 정의합니다.

14. byte를 Digit로 변환하는 연산자가 정의되어 있지만 모든 바이트를 Digit로 변환할 수 있는 것은 아니므로 이 변환은 명시적입니다.


struct Digit
{
    byte value;
    public Digit(byte value)
    {
        if (value > 9)
        {
            throw new ArgumentException();
        }
        this.value = value;
    }

    // Define explicit byte-to-Digit conversion operator:
    public static explicit operator Digit(byte b)
    {
        Digit d = new Digit(b);
        Console.WriteLine("conversion occurred");
        return d;
    }
}

class ExplicitTest
{
    static void Main()
    {
        try
        {
            byte b = 3;
            Digit d = (Digit)b; // explicit conversion
        }
        catch (Exception e)
        {
            Console.WriteLine("{0} Exception caught.", e);
        }
    }
}
/*
Output:
conversion occurred
*/





extern


1. extern 한정자는 외부에서 구현되는(implemented externally) 메서드를 선언하는 데 사용됩니다.

2. extern 한정자는 일반적으로 Interop 서비스를 사용하여 비관리 코드(unmanaged code)를 호출할 때 DllImport 특성과 함께 사용됩니다. 이 경우 다음 에제에서와 같이 메서드를 static으로 선언해야 합니다.

3. 이 경우 다음 예제에서와 같이 메서드를 static으로 선언해야 합니다.


[DllImport("avifil32.dll")]
private static extern void AVIFileInit();


4. extern 키워드는 외부 어셈블리 별칭(external assembly alias)도 정의하여 단일 어셈블리 내에서 동일한 구성 요소(the same component)의 다른 버전을 참조할 수 있도록 합니다.

5. 자세한 내용은 extern alias을 참조하십시오.

6. abstract와 extern 한정자를 함께 사용하여 같은 멤버를 제한할 수는 없습니다.

7. extern 한정자는 메서드가 C# 코드 외부에서 구현됨을 나타내고 abstract 한정자는 해당 클래스에서 메서드가 구현되지 않음을 나타냅니다.

8. extern 키워드는 C++보다 C#에서 사용이 제한적입니다.

9. C# 키워드를 C++ 키워드와 비교하려면 C++ 언어 참조에서 extern을 사용하여 링크 지정(Using extern to Specify Linkage)을 참조하십시오.

10. 다음 예제에서는 프로그램이 사용자로부터 문자열을 수신하여 메시지 상자에 표시합니다.

11. 이 프로그램은 User32.dll 라이브러리에서 가져온 MessageBox 메서드를 사용합니다.


//using System.Runtime.InteropServices;
class ExternTest
{
    [DllImport("User32.dll", CharSet=CharSet.Unicode)] 
    public static extern int MessageBox(IntPtr h, string m, string c, int type);

    static int Main()
    {
        string myString;
        Console.Write("Enter your message: ");
        myString = Console.ReadLine();
        return MessageBox((IntPtr)0, myString, "My Message Box", 0);
    }

}

12. 이 예제는 C 라이브러리(네이티브 DLL)로 호출되는(call into) C# 프로그램을 보여줍니다.

13. 다음 C 파일을 만들고 이름을 cmdll.c로 지정합니다.


// cmdll.c
// Compile with: /LD
int __declspec(dllexport) SampleMethod(int i)
{
   return i*10;
}


14. Visual Studio x64(또는 x32) 네이티브 도구 명령 프롬프트 창을 열고 명령 프롬프트에서 cmdll.c를 입력하여 cl /LD cmdll.c 파일을 컴파일합니다.

15. 같은 디렉터리에서 다음 C# 파일을 만들고 이름을 cm.cs로 지정합니다.


// cm.cs
using System;
using System.Runtime.InteropServices;
public class MainClass 
{
   [DllImport("Cmdll.dll")]
   public static extern int SampleMethod(int x);

   static void Main() 
   {
      Console.WriteLine("SampleMethod() returns {0}.", SampleMethod(5));
   }
}


16. Visual Studio x64(또는 x32) 네이티브 도구 명령 프롬프트 창을 열고 명령 프롬프트에서 다음을 입력하여 cm.cs 파일을 컴파일합니다.


csc cm.cs(x64 명령 프롬프트용) 
—또는—
csc /platform:x86 cm.cs(x32 명령 프롬프트용)


17. 이렇게 하면 실행 파일 cm.exe가 만들어집니다.

18. cm.exe를 실행합니다.

19. SampleMethod method 메서드가 값 5를 DLL 파일로 전달하면 10으로 곱해진 값이 반환됩니다. 프로그램 출력은 다음과 같습니다.


SampleMethod() returns 50.