달력

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. 5. 31. 15:46

C# 키워드 O~S 프로그래밍/C#2016. 5. 31. 15:46

object


1. object 형식은 .NET Framework의 Object에 대한 별칭입니다.

2. C#의 통합된 형식 시스템에서는 미리 정의된 형식과 사용자가 정의한 형식, 참조 형식과 값 형식 같은 모든 형식에 Object에서 직접 또는 간접적으로 상속됩니다.

3. object 형식의 변수에는 모든 형식의 값을 할당할 수 있습니다.

4. 값 형식의 변수를 object 형식으로 변환하는 경우 이를 boxing이라고 합니다.

5. object 형식의 변수를 값 형식으로 변환하는 경우 이를 unboxing이라고 합니다.

6. 자세한 내용은 Boxing 및 Unboxing을 참조하십시오.

7. 다음 예제에서는 object 형식 변수에서 임의의 데이터 형식 값을 수용하는 방법과 object 형식 변수가 .NET Framework에서 Object 메서드를 사용하는 방법에 대해 보여 줍니다.


class ObjectTest
{
   public int i = 10;
}

class MainClass2
{
   static void Main()
   {
      object a;
      a = 1;   // an example of boxing
      Console.WriteLine(a);
      Console.WriteLine(a.GetType());
      Console.WriteLine(a.ToString());

      a = new ObjectTest();
      ObjectTest classRef;
      classRef = (ObjectTest)a;
      Console.WriteLine(classRef.i);
   }
}
/* Output
    1
    System.Int32
    1
 * 10
*/





operator


1. operator 키워드를 사용하여 기본 제공 연산자(a built-in operator)를 오버로드하거나 클래스 또는 구조체 선언에 사용자 정의 변환을 제공할 수 있습니다.

2. 아래 예제는 매우 간단한 분수 클래스(a very simplified class for fractional numbers)입니다.

3. 이 클래스는 + 및 * 연산자를 오버로드하여 분수 더하기(fractional addition)와 곱하기(multiplication)를 수행하고 Fraction 형식을 Double 형식으로 변환하는 변환 연산자도 제공합니다.


class Fraction
{
    int num, den;
    public Fraction(int num, int den)
    {
        this.num = num;
        this.den = den;
    }

    // overload operator +
    public static Fraction operator +(Fraction a, Fraction b)
    {
        return new Fraction(a.num * b.den + b.num * a.den,
           a.den * b.den);
    }

    // overload operator *
    public static Fraction operator *(Fraction a, Fraction b)
    {
        return new Fraction(a.num * b.num, a.den * b.den);
    }

    // user-defined conversion from Fraction to double
    public static implicit operator double(Fraction f)
    {
        return (double)f.num / f.den;
    }
}

class Test
{
    static void Main()
    {
        Fraction a = new Fraction(1, 2);
        Fraction b = new Fraction(3, 7);
        Fraction c = new Fraction(2, 3);
        Console.WriteLine((double)(a * b + c));
    }
}
/*
Output
0.880952380952381
*/





out


1. out 컨텍스트 키워드(contextual keyword)는 두 가지 컨텍스트, 즉 매개 변수 한정자로 사용하거나 인터페이스와 대리자의 제네릭 형식 매개 변수 선언에서 사용할 수 있습니다.

2. 이 항목에서는 매개 변수 한정자에 대해 설명하며, 이 항목에서 제네릭 형식 매개 변수 선언에 대한 정보를 확인할 수 있습니다.

3. out 키워드를 사용하면 참조를 통해 인수(arguments)를 전달(to be passed)할 수 있습니다

4. 이러한 방식은 ref 키워드와 비슷합니다.

5. 단, ref의 경우에는 변수를 전달하기 전에 초기화해야 합니다.

6. out 매개 변수를 사용하려면 메서드 정의(the method definition)와 호출 메서드(the calling method)가 모두 명시적으로 out 키워드를 사용해야 합니다.


class OutExample
{
    static void Method(out int i)
    {
        i = 44;
    }
    static void Main()
    {
        int value;
        Method(out value);
        // value is now 44
    }
}


7. out 인수로 전달되는 변수는 전달하기 전에 초기화할 필요가 없지만 호출되는 메서드는 반환되기 전에 값을 할당해야 합니다.

8. ref 및 out 키워드는 서로 다른 런타임 동작을 수행하지만 컴파일 타임에 메서드 시그니처의 일부로 간주되지는 않습니다. 

9. 따라서 메서드 하나는 ref 인수를 사용하고 다른 하나는 out 인수를 사용하는 것 외에는 차이점이 없으면 메서드를 오버로드할 수 없습니다.

10. 예를 들어 다음 코드는 컴파일되지 않습니다.


class CS0663_Example
{
    // Compiler error CS0663: "Cannot define overloaded 
    // methods that differ only on ref and out".
    public void SampleMethod(out int i) { }
    public void SampleMethod(ref int i) { }
}


11. 그러나 다음과 같이 메서드 하나는 ref 또는 out 인수를 사용하고 다른 하나는 인수를 사용하지 않는 경우에는 오버로드를 수행할 수 있습니다.


class OutOverloadExample
{
    public void SampleMethod(int i) { }
    public void SampleMethod(out int i) { i = 5; }
}


12. 속성(properties)은 변수가 아니므로 out 매개 변수로 전달할 수 없습니다.

13. 배열 전달에 대한 자세한 내용은 ref 및 out을 사용하여 배열 전달을 참조하십시오.

14. ref 및 out 키워드는 다음의 경우와 같은 메소드에서 사용할 수 없습니다.

    1) 비동기 한정자(async modifier)를 사용하여 정의된 비동기 메소드(async methods)

    2) yield return 또는 yield break 문을 포함하는 반복기 메서드(iterator methods)

15. 메서드가 여러 값을 반환하도록 하려는 경우에는 out 메서드를 선언하면 유용합니다.

16. 다음 예제에서는 out을 사용하여 단일 메서드 호출로(with a single method call) 3개 변수를 반환합니다.

17. 세 번재 인수(the third argument)는 null에 할당됩니다.

18. 따라서 메서드가 값을 선택적으로(optionally) 반환할 수 있습니다.


class OutReturnExample
{
    static void Method(out int i, out string s1, out string s2)
    {
        i = 44;
        s1 = "I've been returned";
        s2 = null;
    }
    static void Main()
    {
        int value;
        string str1, str2;
        Method(out value, out str1, out str2);
        // value is now 44
        // str1 is now "I've been returned"
        // str2 is (still) null;
    }
}




out (제네릭 한정자)


1. 제네릭 형식 매개 변수의 경우 out 키워드는 형식 매개 변수가 공변(covariant)임을 나타냅니다.

2. 제네릭 인터페이스와 대리자에서 out 키워드를 사용할 수 있습니다.

3. 공 분산(covariance)을 사용하면 제네릭 매개 변수로 지정된 형식보다 더 많이 파생된 형식을 사용할 수 있습니다.

4. 이 경우 variant 인터페이스를 구현하는 클래스의 암시적 변환과 대리자 형식의 암시적 변환이 가능합니다.

5. 공 분산(covariance) 및 반공 분산(contravariance)은 참조 형식에만 지원되고 값 형식에는 지원되지 않습니다.

6. 공변(covariant) 형식 매개 변수가 있는 인터페이스의 메서드는 형식 매개 변수로 지정된 형식보다 더  많이 파생된 형식을 반환할 수 있습니다.

7. 예를 들어 .NET Framework 4의 IEnumerable<T>에서 형식 T가 공변(covariant)이므로 특수 변환 메서드를 사용하지 않고도 IEnumerable(Of String) 형식의 개체를 IEnumerable(Of Object) 형식의 개체에 할당할 수 있습니다.

8. 공변 대리자는 같은 형식이지만 더 많이 파생된 제네릭 형식 매개 변수를 사용하는 다른 대리자에게 할당할 수 있습니다.

8. 자세한 내용은 공 분산 및 반공 분산을 참조하십시오.

9. 다음 예제에서는 공변(covariant) 제네릭 인터페이스를 선언, 확장(extend) 및 구현하는 방법을 보여 줍니다.

10. 공변 인터페이스를 구현하는 클래스의 암시적 변환을 사용하는 방법도 보여줍니다.


// Covariant interface.
interface ICovariant<out R> { }

// Extending covariant interface.
interface IExtCovariant<out R> : ICovariant<R> { }

// Implementing covariant interface.
class Sample<R> : ICovariant<R> { }

class Program
{
    static void Test()
    {
        ICovariant<Object> iobj = new Sample<Object>();
        ICovariant<String> istr = new Sample<String>();

        // You can assign istr to iobj because
        // the ICovariant interface is covariant.
        iobj = istr;
    }
}


11. 제네릭 인터페이스에서 다음 조건을 충족하는 경우 형식 매개 변수를 공변(covariant)으로 선언할 수 있습니다.

    1) 형식 매개 변수가 인터페이스 메서드의 반환 형식으로만 사용되고 메서드 인수의 형식으로 사용 되지 않는 경우


System_CAPS_note참고

그러나 이 규칙에는 한 가지 예외가 있습니다. 공변(covariant) 인터페이스에서 반공변(contravariant) 제네릭 대리자가 메서드 매개 변수인 경우에는 공변(covariant) 형식을 이 대리자에 대한 제네릭 형식 매개 변수로 사용할 수 있습니다. 공변(covariant) 및 반공변(contravariant) 제네릭 대리자에 대한 자세한 내용은 대리자의 가변성(C# 및 Visual Basic) 및 Func 및 Action 제네릭 대리자에 가변성 사용(C# 및 Visual Basic)을 참조하십시오

    2) 형식 매개 변수가 인터페이스 메서드에 대한 제네릭 제약 조건으로 사용되지 않는 경우


12. 다음 예제에서는 공변(covariant) 제네릭 대리자를 선언, 인스턴스화 및 호출하는 방법을 보여줍니다.

13. 대리자 형식을 암시적으로 변환하는 방법도 보여줍니다.


// Covariant delegate.
public delegate R DCovariant<out R>();

// Methods that match the delegate signature.
public static Control SampleControl()
{ return new Control(); }

public static Button SampleButton()
{ return new Button(); }

public void Test()
{            
    // Instantiate the delegates with the methods.
    DCovariant<Control> dControl = SampleControl;
    DCovariant<Button> dButton = SampleButton;

    // You can assign dButton to dControl
    // because the DCovariant delegate is covariant.
    dControl = dButton;

    // Invoke the delegate.
    dControl(); 
}


14. 메서드 반환 형식으로만 사용되고 메서드 인수로는 사용되지 않는 형식의 경우 제네릭 대리자에서 해당 형식을 공변(covariant)으로 선언할 수 있습니다.\





override


1. override 한정자는 상속된 메서드, 속성, 인덱서 또는 이벤트의 추상 또는 가상 구현을 확장하거나 수정하는 데 필요합니다.

2. 이 예제에서 Area 추상 ShapeClass에서 상속되므로 Square 클래스는 Area의 재정의된 구현(overridden implementation)을 제공해야 합니다.


abstract class ShapesClass
{
    abstract public int Area();
}
class Square : ShapesClass
{
    int side = 0;

    public Square(int n)
    {
        side = n;
    }
    // Area method is required to avoid
    // a compile-time error.
    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


3. override 메서드는 기본 클래스에서 상속된 멤버를 새로 구현합니다.

4. override 선언에 의해 재정의된 메서드를 재정의된 기본 메서드라고 합니다.

5. 재정의된 기본 메서드의 시그니처는 override 메서드의 시그니처와 같아야 합니다.

6. 삭속에 대한 자세한 내용은 상속을 참조하십시오.

7. 비 가상(non-virtual) 메서드 또는 정적(static) 메서드는 재정의할 수 없습니다.

8. 재정의된 기본 메서드는 virtual, abstract 또는 override 메서드이어야 합니다.

9. override 선언을 사용하여 virtual 메서드의 액세스 가능성(accessibility)을 변경할 수 없습니다.

10. override 메서드와 virtual 메서드의 액세스 수준 한정자는 모두 동일합니다.

11. new, static 또는 virtual 한정자를 사용하여 override 메서드를 한정할 수 없습니다.

12. 속성 선언을 재정의할 때는 상속된 속성과 동일한 액세스 한정자, 형식 및 이름을 정확히(exactly) 지정해야 하며 재정의된 속성은 virtual, abstract 또는 override여야 합니다.

13. override 키워드를 사용하는 방법에 대한 자세한 내용은 Override 및 New 키워드를 사용하여 버전 관리Override 및 New 키워드를 사용해야 하는 경우를 참조하십시오.

14. 이 예제에서는 Employee라는 기본 클래스와 SalesEmployee라는 파생 클래스를 정의합니다.

15. SalesEmployee 클래스는 추가 속성 salesbonus를 포함하여 이를 고려하여(in order to take it int account) CalculatePay 메서드를 재정의합니다.


class TestOverride
{
    public class Employee
    {
        public string name;

        // Basepay is defined as protected, so that it may be 
        // accessed only by this class and derrived classes.
        protected decimal basepay;

        // Constructor to set the name and basepay values.
        public Employee(string name, decimal basepay)
        {
            this.name = name;
            this.basepay = basepay;
        }

        // Declared virtual so it can be overridden.
        public virtual decimal CalculatePay()
        {
            return basepay;
        }
    }

    // Derive a new class from Employee.
    public class SalesEmployee : Employee
    {
        // New field that will affect the base pay.
        private decimal salesbonus;

        // The constructor calls the base-class version, and
        // initializes the salesbonus field.
        public SalesEmployee(string name, decimal basepay, 
                  decimal salesbonus) : base(name, basepay)
        {
            this.salesbonus = salesbonus;
        }

        // Override the CalculatePay method 
        // to take bonus into account.
        public override decimal CalculatePay()
        {
            return basepay + salesbonus;
        }
    }

    static void Main()
    {
        // Create some new employees.
        SalesEmployee employee1 = new SalesEmployee("Alice", 
                      1000, 500);
        Employee employee2 = new Employee("Bob", 1200);

        Console.WriteLine("Employee4 " + employee1.name + 
                  " earned: " + employee1.CalculatePay());
        Console.WriteLine("Employee4 " + employee2.name + 
                  " earned: " + employee2.CalculatePay());
    }
}
/*
    Output:
    Employee4 Alice earned: 1500
    Employee4 Bob earned: 1200
*/





params


1. params 키워드를 사용하면 여러 개의 인수를 사용하는(takes a variable number of arguments) 메서드 매개 변수를 지정할 수 있습니다.

2. 매개 변수 선언에 지정된 형식의 쉼표로 구분된 인수 목록(a comma-separated list of arguments) 또는 지정된 형식의 인수 배열을 보낼 수 있습니다.

3. 인수 없이 보낼 수도 있습니다.

4. 인수를 보내지 않으면 params 목록의 길이는 0입니다.

5. 메서드 선언에서 params 키워드 다음에는 매개 변수를 추가할 수 없으며, params 키워드 하나만 메서드 선언에 사용할 수 있습니다(is permitted).

6. 다음 예제에서는 params 매개 변수에 인수를 보낼 수 있는 다양한 방법을 보여 줍니다.


public class MyClass
{
    public static void UseParams(params int[] list)
    {
        for (int i = 0; i < list.Length; i++)
        {
            Console.Write(list[i] + " ");
        }
        Console.WriteLine();
    }

    public static void UseParams2(params object[] list)
    {
        for (int i = 0; i < list.Length; i++)
        {
            Console.Write(list[i] + " ");
        }
        Console.WriteLine();
    }

    static void Main()
    {
        // You can send a comma-separated list of arguments of the 
        // specified type.
        UseParams(1, 2, 3, 4);
        UseParams2(1, 'a', "test");

        // A params parameter accepts zero or more arguments.
        // The following calling statement displays only a blank line.
        UseParams2();

        // An array argument can be passed, as long as the array
        // type matches the parameter type of the method being called.
        int[] myIntArray = { 5, 6, 7, 8, 9 };
        UseParams(myIntArray);

        object[] myObjArray = { 2, 'b', "test", "again" };
        UseParams2(myObjArray);

        // The following call causes a compiler error because the object
        // array cannot be converted into an integer array.
        //UseParams(myObjArray);

        // The following call does not cause an error, but the entire 
        // integer array becomes the first element of the params array.
        UseParams2(myIntArray);
    }
}
/*
Output:
    1 2 3 4
    1 a test

    5 6 7 8 9
    2 b test again
    System.Int32[]
*/





private


1. private 키워드는 멤버 액세스 한정자입니다.

2. private 액세스는 허용도가 가장 낮은 액세스 수준입니다(the least permissive access level).

3. private 멤버는 다음 예제처럼 해당 멤버가 선언되어 있는 클래스 또는 구조체의 본문 내에서만 액세스할 수 있습니다.


class Employee
{
    private int i;
    double d;   // private access by default
}


4. 동일한 본문에서 중첩된 형식(nested types)도 이 private 멤버에 액세스할 수 있습니다.

5. private 멤버가 선언되어 있는 클래스 또는 구조체 외부에서 이 멤버를 참조(reference)하면 컴파일 타임 오류가 발생합니다.

6. private을 다른 액세스 한정자와 비교하려면 액세스 가능성 수준액세스 한정자를 참조하십시오.

7. 이 예제에서 Employee 클래스에는 name과 salary라는 두 개의 전용(private) 데이터 멤버가 포함되어 있습니다.

8. 이들은 private 멤버이므로 멤버 메서드를 사용해야만 액세스할 수 있습니다.

9. private 멤버에 대한 액세스를 제어할 수 있도록 GetName 및 Salary라는 public 메서드가 추가됩니다.

10. name 멤버에는 public 메서드를 사용하여 액세스하고, salary 멤버에는 public 읽기 전용 속성을 통해 액세스합니다.

11. 자세한 내용은 속성을 참조하십시오.


class Employee2
{
    private string name = "FirstName, LastName";
    private double salary = 100.0;

    public string GetName()
    {
        return name;
    }

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

class PrivateTest
{
    static void Main()
    {
        Employee2 e = new Employee2();

        // The data members are inaccessible (private), so
        // they can't be accessed like this:
        //    string n = e.name;
        //    double s = e.salary;

        // 'name' is indirectly accessed via method:
        string n = e.GetName();

        // 'salary' is indirectly accessed via property
        double s = e.Salary;
    }
}





protected


1. protected 키워드는 멤버 액세스 한정자입니다.

2. 보호된 멤버는 해당 클래스 내에서와 파생 클래스 인스턴스에서 액세스할 수 있습니다.

3. 다른 액세스 한정자와 protected를 비교하려면 액세스 가능성 수준을 참조하십시오.

4. 기본 클래스의 보호된 멤버를 파생 클래스에서 액세스할 수 있는 경우는 해당 파생 클래스 형식을 통해 액세스하는 경우뿐입니다.

5. 예를 들어 다음의 코드 세그먼트를 참조하십시오.

 

class A
{
    protected int x = 123;
}

class B : A
{
    static void Main()
    {
        A a = new A();
        B b = new B();

        // Error CS1540, because x can only be accessed by
        // classes derived from A.
        // a.x = 10; 

        // OK, because this class derives from A.
        b.x = 10;
    }
}


6. a.x = 10 문은 클래스 B의 인스턴스가 아니라 정적 메서드인 Main 내에서 만들어지므로 오류를 생성합니다.

7. 구조체는 상속되지 않으므로 구조체 멤버는 보호될 수 없습니다.

8. 이 예제의 경우 DerivedPoint 클래스는 Pint에서 파생됩니다.

9. 따라서 파생된 클래스에서 기본 클래스의 보호된 멤버에 직접 액세스할 수 있습니다.


class Point 
{
    protected int x; 
    protected int y;
}

class DerivedPoint: Point 
{
    static void Main() 
    {
        DerivedPoint dpoint = new DerivedPoint();

        // Direct access to protected members:
        dpoint.x = 10;
        dpoint.y = 15;
        Console.WriteLine("x = {0}, y = {1}", dpoint.x, dpoint.y); 
    }
}
// Output: x = 10, y = 15


10. x 및 y의 액세스 수준을 private으로 변경하면 컴파일러 오류 메시지를 생성합니다(issue).


'Point.y' is inaccessible due to its protection level.


'Point.x' is inaccessible due to its protection level.





public


1. public 키워드는 형식 및 형식 멤버에 대한 액세스 한정자입니다.

2. public 액세스는 허용도가 가장 높은 액세스 수준입니다(the most permissive access leve).

3. 다음 예제처럼 public 멤버는 액세스에 제한이 없습니다(no restrictions on accessing).


class SampleClass
{
    public int x; // No access restrictions.
}


4. 자세한 내용은 액세스 한정자액세스 가능성 수준을 참조하십시오.

5. 다음 예제에서는 두 개의 클래스 PointTest 및 MainClass가 선언되어 있습니다.

6. PointTest의 public 멤버인 x 및 y에는 MainClass에서 직접 액세스할 수 있습니다.


class PointTest
{
    public int x; 
    public int y;
}

class MainClass4
{
    static void Main() 
    {
        PointTest p = new PointTest();
        // Direct access to public members:
        p.x = 10;
        p.y = 15;
        Console.WriteLine("x = {0}, y = {1}", p.x, p.y); 
    }
}
// Output: x = 10, y = 15


7. public 액세스 수준을 private 또는 protected로 변경하면 다음과 같은 오류 메시지가 나타납니다.

8. 보호 수준 때문에 Pointtest.y에 액세스할 수 없습니다.





readonly


1. readonly 키워드는 필드에 사용할 수 있는 한정자입니다.

2. 필드 선언에 readonly 한정자가 포함되어 있으면 선언의 일부로 대입하거나 동일한 클래스의 생성자에서 대입하는 경우에만 선언을 통해 정의한 필드에 값을 대입할 수 있습니다.

3. 이 예제에서 year 필드는 클래스 생성자에서 값이 할당된 경우라도 ChangeYear 메서드로 값을 변경할 수 없습니다.


class Age
{
    readonly int _year;
    Age(int year)
    {
        _year = year;
    }
    void ChangeYear()
    {
        //_year = 1967; // Compile error if uncommented.
    }
}


4. 다음 경우에만 readonly 필드에 값을 대입할 수 있습니다.


public readonly int y = 5;


5. 인스턴스 필드의 경우 필드 선언이 포함된 클래스의 인스턴스 생성자에서 값을 대입할 수 있으며, 정적 필드의 경우에는 필드 선언이 포함된 클래스의 정적 생성자에서 값을 대입할 수 있습니다.

6. 위의 두 경우는 readonly 필드를 out 또는 ref 매개 변수로 전달할 수 있는 유일한 경우이기도 합니다.


System_CAPS_note참고

readonly 키워드는 const 키워드와 다릅니다. const 필드는 필드를 선언할 때만 초기화될 수 있습니다. readonly 필드는 필드를 선언할 때 또는 생성자에서 초기화될 수 있습니다. 따라서 readonly 필드의 값은 사용된 생성자에 따라 다릅니다. 또한 const 필드는 컴파일 타임 상수인 반면 readonly필드는 다음 예제에서와 같이 런타임 상수로도 사용할 수 있습니다.

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


public class ReadOnlyTest
{
   class SampleClass
   {
      public int x;
      // Initialize a readonly field
      public readonly int y = 25;
      public readonly int z;

      public SampleClass()
      {
         // Initialize a readonly instance field
         z = 24;
      }

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

   static void Main()
   {
      SampleClass p1 = new SampleClass(11, 21, 32);   // OK
      Console.WriteLine("p1: x={0}, y={1}, z={2}", p1.x, p1.y, p1.z);
      SampleClass p2 = new SampleClass();
      p2.x = 55;   // OK
      Console.WriteLine("p2: x={0}, y={1}, z={2}", p2.x, p2.y, p2.z);
   }
}
/*
 Output:
    p1: x=11, y=21, z=32
    p2: x=55, y=25, z=24
*/


7. 앞의 예제에서 다음과 같은 문을 사용하면 

    p2.y = 66; // 오류

8. 다음과 같은 컴파일러 오류가 메시지가 발생합니다.

    The left-hand side of an assignment must be an l-value

9. 이 오류는 상수에 값을 대입할 때 발생하는 오류와 동일합니다.





ref


1. ref 키워드는 인수(argument)가 값의 복사가 아닌 참조로 전달되도록 합니다.

2. 인수를 참조로 전달하는 경우 호출된 메서드의 매개 변수 변경 내용이 호출 메서드에 반영됩니다(is reflected in the calling method).

3. 예를 들어 호출자가 로컬 변수 식 또는 배열 요소 액세스 식을 전달하는 경우 호출된 메서드에서 ref 매개 변수가 참조하는 개체를 바꾸면 호출자의 로컬 변수 또는 배열 요소가 새 개체를 참조합니다.

System_CAPS_note참고

참조에 의한 전달 개념을 참조 형식의 개념과 혼동하지 마십시오. 이 두 개념은 서로 다릅니다. 메서드 매개 변수는, 값 형식이든 참조 형식이든 관계없이 ref로 수정될 수 있습니다. 참조로 전달되는 경우 값 형식은 boxing되지 않습니다.

4. ref 매개 변수를 사용하려면, 다음 예제처럼 메서드 정의와 메서드 호출 양쪽 모두 ref 키워드를 명시적으로 사용해야 합니다.


class RefExample
{
    static void Method(ref int i)
    {
        // Rest the mouse pointer over i to verify that it is an int.
        // The following statement would cause a compiler error if i
        // were boxed as an object.
        i = i + 44;
    }

    static void Main()
    {
        int val = 1;
        Method(ref val);
        Console.WriteLine(val);

        // Output: 45
    }
}


5. ref 매개 변수와 전달되는 인수는 전달되기 전에 초기화해야 합니다.

6. 이러한 방식은 인수를 전달하기 전에 명시적으로 초기화할 필요가 없는 out 매개변수와는 다릅니다.

7. 자세한 내용은 out을 참조하세요.

8. 클래스의 멤버는 ref 및 out 만 다른 서명을 포함할 수 없습니다.

9. 특정 형식의 두 멤버가 하나는 ref 매개 변수를 포함하고 다른 하나는 out 매개 변수를 포함한다는 것 외에는 차이가 없으면 컴파일러 오류가 발생합니다.

10. 예를 들어 다음 코드는 컴파일되지 않습니다.


class CS0663_Example
{
    // Compiler error CS0663: "Cannot define overloaded 
    // methods that differ only on ref and out".
    public void SampleMethod(out int i) { }
    public void SampleMethod(ref int i) { }
}


11. 그러나 한쪽 메서드에 ref 또는 out 매개 변수가 한 개 있고, 다른 쪽에 값 매개 변수가 한 개 있을 경우, 다음 예제와 같이 오버로딩될 수 있습니다.


class RefOverloadExample
{
    public void SampleMethod(int i) { }
    public void SampleMethod(ref int i) { }
}


12. 숨기기(hiding)나 재정의(overring)과 같이 시그니처가 필요한 다른 상황에서는 ref 및 out이 서명의 일부가 되며 서로 일치하지 않습니다.

13. 속성(properties)은 변수가 아니라 메서드이며 ref 매개 변수로 전달할 수 없습니다.

14. 배열을 전달하는 방법에 대한 자세한 내용은 ref 및 out을 사용하여 배열 전달을 참조하세요.

15. ref 및 out 키워드는 다음의 경우와 같은 메소드에서 사용할 수 없습니다.

    1) 비동기(async) 한정자를 사용하여 정의된 비동기(async) 메서드

    2) yield return 또는 yield break 문을 포함하는 반복기 메서드

16. 위의 예제에서는 값 형식을 참조로 전달하는 경우의 결과를 보여줍니다.

17. ref 키워드를 사용하여 참조 형식을 전달할 수도 있습니다.

18. 참조 형식을 참조로 전달하는 경우 호출된 메서드는 참조 매개 변수가 참조하는 호출 메서드의 개체를 바꿀 수 있습니다.

19. 개체의 저장 위치는 참조 매개변수의 값으로 메서드에 전달됩니다.

20. 매개 변수의 저장 위치에서 값을 변경하여 새 개체를 가리키도록 하면 호출자가 참조하는 저장 위치도 변경됩니다.

21. 다음 예제에서는 참조 형식 인스턴스를 ref 매개 변수로 전달합니다.

22. 참조 형식을 값 및 참조로 전달하는 방법에 대한 자세한 내용은 참조 형식 매개 변수 전달을 참조하세요.


class RefExample2
{
    static void ChangeByReference(ref Product itemRef)
    {
        // The following line changes the address that is stored in  
        // parameter itemRef. Because itemRef is a ref parameter, the
        // address that is stored in variable item in Main also is changed.
        itemRef = new Product("Stapler", 99999);

        // You can change the value of one of the properties of
        // itemRef. The change happens to item in Main as well.
        itemRef.ItemID = 12345;
    }

    static void Main()
    {
        // Declare an instance of Product and display its initial values.
        Product item = new Product("Fasteners", 54321);
        System.Console.WriteLine("Original values in Main.  Name: {0}, ID: {1}\n",
            item.ItemName, item.ItemID);

        // Send item to ChangeByReference as a ref argument.
        ChangeByReference(ref item);
        System.Console.WriteLine("Back in Main.  Name: {0}, ID: {1}\n",
            item.ItemName, item.ItemID);
    }
}

class Product
{
    public Product(string name, int newID)
    {
        ItemName = name;
        ItemID = newID;
    }

    public string ItemName { get; set; }
    public int ItemID { get; set; }
}

// Output: 
//Original values in Main.  Name: Fasteners, ID: 54321

//Back in Main.  Name: Stapler, ID: 12345





return


1. return 문은 자신이 속한 메서드의 실행을 종료하고 호출한 메서드로 제어를 반환합니다.

2. 선택적 값을 반환할 수도 있습니다.

3. void 형식의 메서드인 경우 return 문을 생략(omit)할 수 있습니다.

4. return 문이 try 블록 내부에 있을 경우 finally 블록이 존재한다면 호출 메서드로 컨트롤을 반환하기 전에 해당 블록이 실행됩니다.


class ReturnTest
{
    static double CalculateArea(int r)
    {
        double area = r * r * Math.PI;
        return area;
    }

    static void Main()
    {
        int radius = 5;
        double result = CalculateArea(radius);
        Console.WriteLine("The area is {0:0.00}", result);

        // Keep the console open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}
// Output: The area is 78.54





sbyte


1. sbyte 키워드는 다음 표에 표시된 크기와 범위에 따라 값을 저장하는 정수 계열

형식

범위

크기

.NET Framework 형식

sbyte

-128 ~ 127

부호 있는 8비트 정수

System.SByte

2. 다음과 같은 방식(in this manner)으로 sbyte 변수를 선언하고 초기화할 수 있습니다.


sbyte sByte1 = 127;


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

4. 정수 리터럴이 sbyte 범위를 초과하면 컴파일 오류(a compilation error)가 발생합니다.

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

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


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


7. 이 경우, sbyte 캐스트를 사용하면 올바른 형식이 호출됩니다. 예를 들면 다음과 같습니다.


// Calling the method with the int parameter:
SampleMethod(5);
// Calling the method with the sbyte parameter:
SampleMethod((sbyte)5);


8. sbyte에서 short, int, long, float, double 또는 decimal로의 미리 정의된 암시적 변환이 있습니다.

9. 저장 크기가 더 큰 비 리터럴 숫자 형식(nonliteral numeric types)은 암시적으로 sbyte로 변환할 수 없습니다.

10. 정수 계열 형식의 저장 크기에 대해서는 정수 계열 형식 표를 참조하십시오.

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


sbyte x = 10, y = 20;


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


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


13. 이 문제를 해결하려면 식을 다음의 예제와 같이 캐스팅합니다.


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


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


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


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

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


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


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

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





sealed


1. 클래스에 적용될 경우 sealed 한정자는 다른 클래스가 해당 클래스에서 상속하지 않도록 합니다.

2. 다음 예제에서 B 클래스는 A 클래스에서 상속하지만 B 클래스에서 상속할 수 있는 클래스는 없습니다.


class A {}    
sealed class B : A {}


3. 기본 클래스의 가상 메서드나 속성을 재정의하는 메서드 또는 속성에 sealed 한정자를 사용할 수도 있습니다.

4. 이렇게 하면 클래스에서 클래스를 파생시키고, 해당 클래스에서 특정 가상 메서드나 속성을 재정의하지 못하도록 할 수 있습니다.

5. 다음 예제에서 Z는 Y에서 상속하지만 Z는 X에 선언되고 Y에 봉인된(sealed) 가상 함수 F를 재정의할 수 없습니다.


class X
{
    protected virtual void F() { Console.WriteLine("X.F"); }
    protected virtual void F2() { Console.WriteLine("X.F2"); }
}
class Y : X
{
    sealed protected override void F() { Console.WriteLine("Y.F"); }
    protected override void F2() { Console.WriteLine("Y.F2"); }
}
class Z : Y
{
    // Attempting to override F causes compiler error CS0239.
    // protected override void F() { Console.WriteLine("C.F"); }

    // Overriding F2 is allowed.
    protected override void F2() { Console.WriteLine("Z.F2"); }
}


6. 클래스의 새 메서드 또는 속성을 정의할 때 virtual로 선언하지 않으면 파생 클래스(deriving classes)가 재정의되지 않도록 할 수 있습니다.

7. 추상 클래스는 추상 메서드 또는 속성의 구현을 제공하는 클래스에서 상속해야 하므로 봉인 클래스와 함께 abstract 한정자를 사용하면 오류가 발생합니다

8. 메서드나 속성에 sealed 한정자를 적용하는 경우 항상 override를 함께 사용해야 합니다.

9. 구조체는 암시적으로 봉인되므로 상속할 수 없습니다.

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

11. 추가 예제는 추상 및 봉인 클래스와 클래스 멤버를 참조하십시오.


sealed class SealedClass
{
    public int x;
    public int y;
}

class SealedTest2
{
    static void Main()
    {
        SealedClass sc = new SealedClass();
        sc.x = 110;
        sc.y = 150;
        Console.WriteLine("x = {0}, y = {1}", sc.x, sc.y);
    }
}
// Output: x = 110, y = 150


12. 위 예제에서 다음 문을 사용하여 봉인 클래스에서 상속할 경우

     class MyDerivedC: SealedClass {} // Error

13. 다음 오류 메시지가 나타납니다.

     'MyDerivedC' cannot inherit from sealed class 'SealedClass'.

14. 클래스, 메서드, 속성을 봉인할지 여부를 결정하려면 일반적으로 다음 두 가지 사항을 고려해야 합니다.

     1) 파생 클래스가 클래스를 커스터마이즈(customize)해서 얻을 수 있는 잠재적 이점(the potential benefits)

     2) 파생 클래스에서 클래스를 수정하여 해당 클래스가 더이상 올바르게(correctly) 또는 예상대로(as expected) 작동(work)하지 않게 될 가능성(the potential)




short


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

형식

범위

크기

.NET Framework 형식

short

-32,768 ~ 32,767

부호 있는 16비트 정수

System.Int16

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


short x = 32767;


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

4. 정수 리터럴이 short 저장소 위치에 맞지 않는(fit into) 경우 컴파일 오류가 발생합니다.

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

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


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


7. 이 경우 short 캐스트를 사용하면 올바른 형식(correct type)이 호출되는 것을 보장합니다(guarantee).


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


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

9. 저장 크기가 더 큰(larger storage size) 비 리터럴 숫자 형식은 암시적으로 short로 변환할 수 없습니다.

10. 정수 계열 형식의 저장 크기에 대해서는 정수 계열 형식 표를 참조하십시오.

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


short x = 5, y = 12;


12. 이 경우 다음 대입문에서는 컴파일 오류가 발생합니다.

13. 그 이유는 대입 연산자의 오른쪽에 있는 산술식이 기본적으로 int로 계산되기 때문입니다.


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


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


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


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


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


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

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


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


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

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





sizeof


1. 관리되지 않는 형식(an unmanaged type)에 대한 바이트 단위의 크기를 가져오는 데(obtain) 사용됩니다.

2. 관리되지 않는 형식에는 다음 표에 나열된 기본 제공 형식뿐 아니라 다음 형식도 포함됩니ㅏㄷ.

    1) 열거형 형식(Enum types)

    2) 포인터 형식(Pointer types)

    3) 참조 형식인 필드나 속성을 포함하지 않는 사용자 정의 구조체

3. 다음 예제에서는 int의 크기를 검색하는 방법을 보여줍니다.


// Constant value 4:
int intSize = sizeof(int); 


4. C# 버전 2.0부터는 기본 제공 형식에 sizeof를 적용할 때 unsafe 모드를 사용하지 않아도 됩니다

5. sizeof 연산자는 오버로드되지 않습니다.

6. sizeof 연산자가 반환하는 값은 int 형식입니다.

7. 다음 표에서는 특정 기본 제공 형식을 피연산자로 사용하는 sizeof 식 대신 사용되는(is substituted for) 상수 값을 보여줍니다.

상수 값

sizeof(sbyte)

1

sizeof(byte)

1

sizeof(short)

2

sizeof(ushort)

2

sizeof(int)

4

sizeof(uint)

4

sizeof(long)

8

sizeof(ulong)

8

sizeof(char)

2(유니코드)

sizeof(float)

4

sizeof(double)

8

sizeof(decimal)

16

sizeof(bool)

1

8. 구조체를 포함한 다른 모든 형식의 경우에는 안전하지 않은 코드 블록(unsafe code blocks)에서만 sizeof 연산자를 사용할 수 있습니다.

9. Marshal.SizeOf 메서드를 사용할 수 있지만 이 메서드가 반환하는 값이 sizeof가 반환하는 값과 항상 같지는 않습니다.

10. Marshal.SizeOf는 형식이 마샬링된 후의 크기를 반환하지만 sizeof는 패딩을 포함하여 공용 언어 런타임(CLR)에서 할당된 크기를 반환합니다.


class MainClass
{
    // unsafe not required for primitive types
    static void Main()
    {
        Console.WriteLine("The size of short is {0}.", sizeof(short));
        Console.WriteLine("The size of int is {0}.", sizeof(int));
        Console.WriteLine("The size of long is {0}.", sizeof(long));
    }
}
/*
Output:
    The size of short is 2.
    The size of int is 4.
    The size of long is 8.
*/





stackalloc


1. stackalloc 키워드는 안전하지 않은 코드 컨텍스트에서 스택에 메모리 블록을 할당하는 데 사용됩니다.


int* block = stackalloc int[100];


2. 키워드는 지역 변수 이니셜라이저에서만 유효합니다.

3. 다음 코드는 컴파일러 오류를 발생시킵니다.


int* block;
// The following assignment statement causes compiler errors. You
// can use stackalloc only when declaring and initializing a local 
// variable.
block = stackalloc int[100];


4. 포인터 형식이 관련되기(involved) 때문에 stackalloc에는 unsafe 컨텍스트가 필요합니다.

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

6. stackalloc는 C 런타임 라이브러리의 _alloca와 비슷합니다.

7. 다음 예제는 피보나치 수열(the Fibonacci sequence)의 20번째 숫자까지 계산 및 표시합니다.

8. 각 번호에는 이전 두 숫자의 합계입니다.

9. 이 코드에서 int 형식의 요소 100개를 포함하는 데 충분한 크기의 메모리 블록은 힙이 아니라 스택에 할당됩니다.

10. 블록의 주소는 포인터 fib에 저장됩니다.

11. 이 메모리는 가비지 수집의 영향을 받지 않으므로(is not subject to) fixed를 사용하여 고정(pin)하지 않아도 됩니다.

12. 메모리 블록의 수명(lifetime)은 해당 메모리 블록이 정의된 메서드의 수명에 따라 제한됩니다.

13. 즉, 메서드가 반환하기 전에는 메모리를 해제(free)할 수 없습니다.


class Test
{
    static unsafe void Main()
    {
        const int arraySize = 20;
        int* fib = stackalloc int[arraySize];
        int* p = fib;
        // The sequence begins with 1, 1.
        *p++ = *p++ = 1;
        for (int i = 2; i < arraySize; ++i, ++p)
        {
            // Sum the previous two numbers.
            *p = p[-1] + p[-2];
        }
        for (int i = 0; i < arraySize; ++i)
        {
            Console.WriteLine(fib[i]);
        }

        // Keep the console window open in debug mode.
        System.Console.WriteLine("Press any key to exit.");
        System.Console.ReadKey();
    }
}
/*
Output
1
1
2
3
5
8
13
21
34
55
89
144
233
377
610
987
1597
2584
4181
6765
*/


14. 안전하지 않은 코드는 안전한 코드보다 위험합니다.

15. 그러나 stackalloc을 사용하면 CLR(공용 언어 런타임)에서 버퍼 오버런 감지 기능(buffer overrun detection features)이 자동으로 활성화됩니다.

16. 버퍼 오버런을 감지(detect)하면 프로세스가 가능한 한 신속하게 종료되어 악의적인 코드(malicious code)가 실행될 가능성을 최소화(minimize the chance)합니다.





static


1. static 한정자는 특정 개체가 아니라 해당 형식 자체에 속하는 정적 멤버를 선언하는 데 사용됩니다.

2. static 한정자는 클래스, 필드, 메서드, 속성, 연산자, 이벤트 및 생성자와 함께 사용할 수 있지만 클래스 이외의 형식(types other than classes), 소멸자(destructors) 또는 인덱서와는 함께 사용할 수 없습니다.

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

4. 다음 클래스는 static으로 선언되며 static 메서드만 포함됩니다.


static class CompanyEmployee
{
    public static void DoSomething() { /*...*/ }
    public static void DoSomethingElse() { /*...*/  }
}


6. 상수 또는 형식 선언은 암시적으로 정적 멤버입니다.

7. 정적 멤버는 인스턴스를 통해 참조할 수 없습니다

8. 대신 형식 이름(the type name)을 통해 참조됩니다.

9. 예를 들어 다음 클래스를 확인해 보십시오.


public class MyBaseC
{
    public struct MyStruct
    {
        public static int x = 100;
    }
}

10. 정적 멤버 x를 참조하려면 동일한 범위에서 멤버에 액세스 가능하지 않은 정규화된 이름(the fully qualified name) MyBaseC.MyStruct.x을 사용합니다.


Console.WriteLine(MyBaseC.MyStruct.x);


11. 클래스의 인스턴스에는 해당 클래스의 모든 인스턴스 필드에 대한 별도의 복사본이 포함되지만 각 정적 필드의 복사본은 한 개만 있습니다.

12. this를 사용하여 정적 메서드 또는 속성 접근자(property accessors)를 참조할 수 없습니다.

13. 클래스에 static 키워드가 적용되면 해당 클래스의 모든 멤버가 정적 멤버여야 합니다.

14. 클래스와 정적 클래스는 정적 생성자를 가질 수 있습니다.

15. 정적 생성자(static constructors)는 프로그램이 시작된 후 클래스가 인스턴스되기 전에 호출됩니다.

System_CAPS_note참고

static 키워드는 C++에서보다 더 제한적으로 사용됩니다. C++ 키워드와 비교하려면 Static (C++)을 참조하십시오.

16. 정적 멤버를 설명하기 위해 회사의 직원을 나타내는 클래스가 있다고 가정합니다.

17. 또한 이 클래스에 직원 수를 계산하는 메서드와 직원 수를 저장하기 위한 필드가 포함되어 있다고 가정합니다(assume)

18. 이 메서드와 필드는 모두 어떤 인스턴스 직원에도 속해 있지 않습니다.

19. 대신 회사 클래스에 속해 있습니다.

20. 따라서 이 메서드 및 필드는 해당 클래스의 정적 멤버로 선언되어야 합니다.

21. 이 예제에서는 새 직원의 이름 및 ID를 읽고 직원 카운터를 1씩 증가시키고 새로운 직원 수와 새 직원에 대한 정보를 표시합니다.

22. 간단하게 설명하기 위해(For simplicity) 이 프로그램은 키보드를 통해 직원의 현재 수를 읽어 들입니다.

23. 실제 응용 프로그램에서는(In a real application) 이 정보를 파일에서 읽어 드립니다.


public class Employee4
{
    public string id;
    public string name;

    public Employee4()
    {
    }

    public Employee4(string name, string id)
    {
        this.name = name;
        this.id = id;
    }

    public static int employeeCounter;

    public static int AddEmployee()
    {
        return ++employeeCounter;
    }
}

class MainClass : Employee4
{
    static void Main()
    {
        Console.Write("Enter the employee's name: ");
        string name = Console.ReadLine();
        Console.Write("Enter the employee's ID: ");
        string id = Console.ReadLine();

        // Create and configure the employee object:
        Employee4 e = new Employee4(name, id);
        Console.Write("Enter the current number of employees: ");
        string n = Console.ReadLine();
        Employee4.employeeCounter = Int32.Parse(n);
        Employee4.AddEmployee();

        // Display the new information:
        Console.WriteLine("Name: {0}", e.name);
        Console.WriteLine("ID:   {0}", e.id);
        Console.WriteLine("New Number of Employees: {0}",
                      Employee4.employeeCounter);
    }
}
    /*
    Input:
    Matthias Berndt
    AF643G
    15
     * 
    Sample Output:
    Enter the employee's name: Matthias Berndt
    Enter the employee's ID: AF643G
    Enter the current number of employees: 15
    Name: Matthias Berndt
    ID:   AF643G
    New Number of Employees: 16
    */


24. 이 예제에서는 아직 선언되지 않은 다른 정적 필드를 사용하여 정적 필드를 초기화할 수 있지만 그 결과는 정적 필드에 명시적으로 값을 할당하기 전까지 정의되지 않은 상태임을 보여 줍니다.





string


1. string 형식은 0개 이상의 유니코드 문자 시퀀스를 나타냅니다.

2. string은 .NET Framework의 String에 대한 별칭입니다.

3. string은 참조 형식이지만 같음 연산자(== 및 !=)(the equality operators)는 참조가 아니라 string 개체의 값을 비교하도록 정의되어 있으므로 좀 더 쉽게 문자열을 비교할 수 있습니다.


string a = "hello";
string b = "h";
// Append to contents of 'b'
b += "ello";
Console.WriteLine(a == b);
Console.WriteLine((object)a == (object)b);


4. 이 코드는 "True"를 표시한 다음 "False"를 표시하는데, 이는 문자열의 내용이 동일(equivalent)하지만 a와 b는 동일한 문자열 인스턴스를 가리키지 않기 때문입니다.

5. + 연산자는 문자열을 연결합니다(concatenate).


string a = "good " + "morning";


6. 문자열은 변경할 수 없습니다(immutable).

7. 즉, 구문을 보면 문자열 개체를 만든 후 이 개체의 내용을 변경할 수 있는 것처럼 보이지만 이는 가능하지 않습니다.

8. 예를 들어, 다음 코드를 작성하면 컴파일러에서는 새 문자 시퀀스가 있는 새 문자열 개체를 만들어 새 개체에 b가 할당됩니다.


string b = "h";
b += "ello";


9. [] 연산자는 string의 개별 문자에 읽기 전용으로 액세스하는 데 사용할 수 있습니다.


string str = "test";
char x = str[2];  // x = 's';


10. 문자열 리터럴은 string 형식이며 따옴표 붙은 형식과 @-따옴표 붙은 형식의 두 가지 형태로 작성할 수 있습니다.

11. 따옴표 붙은 문자열 리터럴은 다음과 같이 큰따옴표(")(double quotation marks)로 묶습니다(enclosed).


"good morning"  // a string literal


12. 문자열 리터럴에는 다음과 같이 이스케이프 시퀀스를 포함한 모든 문자 리터럴이 포함될 수 있습니다.

13. 다음 예제에서는 백슬래시에 이스케이프 시퀀스 \\, 글자 f에  \u0066, 줄 바꿈 \n을 사용합니다.


string a = "\\\u0066\n";
Console.WriteLine(a);


System_CAPS_note참고

이스케이프 코드 \udddd는 유니코드 문자 U+dddd를 나타냅니다. 여기서 dddd는 네 자리 숫자입니다. \Udddddddd와 같은 8자리 유니코드 이스케이프 코드도 사용할 수 있습니다.

14. 약어 문자열 리터럴(verbatim string literals)은 @로 시작하며 큰따옴표로 묶습니다.


@"good morning"  // a string literal


15. 약어 문자열의 이점(the advantage)은 이스케이프 시퀀스를 처리하지 않기 때문에 다음과 같이 정규화된 파일 이름 등을 쉽게 작성할 수 있다는 것입니다.


@"c:\Docs\Source\a.txt"  // rather than "c:\\Docs\\Source\\a.txt"


16. @-따옴표 붙은 문자열에 큰따옴표를 포함시키려면 다음과 같이 큰따옴표를 두 번 입력합니다(double it).


@"""Ahoy!"" cried the captain." // "Ahoy!" cried the captain.


17. 또한 @ 기호는 C# 키워드인 참조된 식별자(/reference)를 사용하는 데 유용합니다.

18. C# 문자열에 대한 자세한 내용은 문자열을 참조하십시오.


class SimpleStringTest 
{
   static void Main()
   {
      string a = "\u0068ello ";
      string b = "world";
      Console.WriteLine( a + b );
      Console.WriteLine( a + b == "Hello World" ); // == performs a case-sensitive comparison
   }
}
/* Output:
    hello world
    False
 */





struct


1. struct 형식은 인벤토리 항목 특성(the characteristics of an item))이나 사각형의 좌표(the coordinates of a rectangle)와 같은 관련 변수의 소규모 그룹을 캡슐화(encapsulate)하는 데 일반적으로 사용되는 값 형식입니다.

2. 다음 예제에서는 간단한 구조체 선언을 보여줍니다.


public struct Book
{
    public decimal price;
    public string title;
    public string author;
}


3. 구조체는 생성자, 상수, 필드, 메서드, 속성, 인덱서, 연산자, 이벤트중첩 형식도 포함할 수 있습니다.

4. 그러나 이러한 멤버가 여러 개 필요한 경우에는 구조체 대신 클래스 형식을 지정하는 것이 좋습니다.

5. 예제를 보려면 구조체 사용을 참조하십시오.

6. 구조체는 인터페이스를 구현할 수는 있지만 다른 구조체를 상속할 수는 없습니다.

7. 그러므로 구조체 멤버를 protected로 선언할 수는 없습니다.

8. 자세한 내용은 구조체를 참조하십시오.





switch


1. case 참조


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

C# 컨텍스트 키워드  (0) 2016.06.06
C# 키워드 T~Z  (0) 2016.06.03
C# 키워드 F~N  (0) 2016.05.21
C# 키워드 A-E  (0) 2016.05.13
연산자 2  (0) 2016.05.10
:
Posted by 지훈2
2016. 5. 21. 15:14

C# 키워드 F~N 프로그래밍/C#2016. 5. 21. 15:14

false 연산자


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

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

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

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

5. nullable Boolean으로 a != b 식은 두 값 중 하나 이상이 null일 수 있으므로 !(a==b)과 반드시 일치하지는 않습니다.

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

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


// 예시용입니다. 가능하면 내장(built-in) nullable bool 형식(bool?)을 사용하세요. public struct DBBool { // 세 개의 가능한 DBBool 값들. public static readonly DBBool Null = new DBBool(0); public static readonly DBBool False = new DBBool(-1); public static readonly DBBool True = new DBBool(1); // False, Null, True에 대한 -1, 0, 1 을 저장하는 Private 필드 sbyte value; // Private 인스턴스 생상자 매개변수 값은 -1, 0, 1이어야 합니다. DBBool(int value) { this.value = (sbyte)value; } // DBBool의 값을 검사하는 속성. // 만약 DBBool 이 주어진 값을 가지고 있다면 true 반환, 그렇지 않으면 false 반환 public bool IsNull { get { return value == 0; } } public bool IsFalse { get { return value < 0; } } public bool IsTrue { get { return value > 0; } } // bool에서 DBBool로의 암시적 변환 // DBBool.True에 true를, DBBool.False에 false를 대입 public static implicit operator DBBool(bool x) { return x ? True : False; } // DBBool에서 bool로의 명시적 변환. // 주어진 DBBool이 Null이라면 예외를 Throw한다. 그렇지 않으면 true 또는 false 반환 public static explicit operator bool(DBBool x) { if (x.value == 0) throw new InvalidOperationException(); return x.value > 0; } // 균등 연산자(Equality operator). // 한 쪽 피연산자가 Null이면 Null 반환, 그렇지 않으면 True 또는 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 // 한 쪽 피연산자가 Null이면 Null 반환, 그렇지 않으면 True, 또는 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; } // 논리 부정 연산자. 피연산자가 False이면 True 반환 // 피연산자가 Null이면 Null 반환, 피연산자가 True이면 False 반환 public static DBBool operator !(DBBool x) { return new DBBool(-x.value); } // 논리 AND 연산자. Returns False if either operand is False, // 한 쪽 피연산자가 False이면 False 반환, Null이면 Null 반환, 그렇지 않으면 True 반환 public static DBBool operator &(DBBool x, DBBool y) { return new DBBool(x.value < y.value ? x.value : y.value); } // 논리 OR 연산자. 한 쪽 피연산자가 True이면 True 반환 // 한 쪽 피연산자가 Null이면 Null 반환. 그렇지 않으면 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 문과 조건식에서 제어식에 사용할 수 있습니다.

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

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





false 리터럴


1. boolean 값 false를 나타냅니다.


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





try-finally


1. finally 블록을 사용하여 try 블록에 할당된 리소스를 정리(clean up)하고 try 블록에 예외가 발생하더라도 코드를 실행할 수 있습니다.

2. 일반적으로(typically), 제어가 try 문을 나갈 때 finally 블록 문이 실행됩니다.

3. 제어 이동은 일반 실행(normal execution), break, continue, goto, return 문 실행 또는 try 문에서 예외 전파(propagation)의 결과로 발생할 수 있습니다.

4. 처리된 예외(handled exception) 안에서는 연결된 finally 블록이 반드시 실행됩니다.(is guaranteed to be run)

5. 그러나 예외가 처리되지 않은 경우, finally 블록은 예외 해제 작업(exception unwind operation)이 트리거되는 방법에 따라 다르게 실행됩니다.

6. 이것도 컴퓨터 설정 방법에 따라 다릅니다.

7. 자세한 내용은 Unhandled Exception Processing in the CLR을 찹조하십시오.

8. 일반적으로(Usually), 처리되지 않은 예외로 응용 프로그램이 종료되면, finally 블록의 실행 여부는 중요하지 않습니다.

9. 그러나 이러한 상황에서도 실행되어야 하는 finally 블록의 문이 있는 경우 하나의 솔루션은 catch 블록을 try-finally 문에 추가하는 것입니다.

10. 또는(Alternatively), 높은 호출 스택(higher up the call stack)에 있는 try-finally의 try 블록에서 throw될 수 있는 예외를 catch할 수 있습니다.

11. try-finally 문이 포함된 메서드를 호출하는 메서드에서, 이 메서드를 호출하는 메서드에서 또는 호출 스택의 모든 메서드에서 예외를 catch할 수 있습니다.

12. 예외가 catch되지 않는 경우 finally 블록은 운영 체제에서 예외 해제 작업을 트리거하도록 선택하는지 여부에 따라 다르게 실행됩니다.

13. 아래 예제에서는 잘못된 변환문(an invalid conversion statement)이 System.InvalidCastException 예외를 발생시킵니다.

14. 예외는 처리되지 않습니다.


public class ThrowTestA { static void Main() { int i = 123; string s = "Some string"; object obj = s; try { // 잘못된 변환; obj는 숫자형(numeric type)이 아닌 문자열(string)을 포함한다. i = (int)obj; // 다음 문은 실행되지 않는다. Console.WriteLine("WriteLine at the end of the try block."); } finally { // Visual Studio에서 프로그램을 실행하려면 CTRL+F5를 누루세요. // 그리고 오류 창에서 취소를 클릭하세요. Console.WriteLine("\nExecution of the finally block after an unhandled\n" + "error depends on how the exception unwind operation is triggered."); Console.WriteLine("i = {0}", i); } } // Output: // Unhandled Exception: System.InvalidCastException: Specified cast is not valid. // // Execution of the finally block after an unhandled // error depends on how the exception unwind operation is triggered. // i = 123 }


15. 다음 예에서 TryCast 메서드의 예외는 호출 스택의 멀리 있는 메서드에서(in a method farther up the call stack) catch 됩니다.


public class ThrowTestB { static void Main() { try { // TryCast 처리되지 않은 예외를 발생시킵니다(produce). TryCast(); } catch (Exception ex) { // TryCast에서 처리되지 않은 예외를 catch 합니다. Console.WriteLine ("Catching the {0} exception triggers the finally block.", ex.GetType()); // 원래의 처리되지 않은 예외를 복구합니다. // 어떤 예외가 나타날지 어떻게 처리할지 모르기 때문에 예외를 throw합니다. throw; } } public static void TryCast() { int i = 123; string s = "Some string"; object obj = s; try { // 잘못된 변환, obj는 숫자 형식이 아닌 문자열을 포함합니다.. i = (int)obj; // 다음 문은 실행되지 않습니다. Console.WriteLine("WriteLine at the end of the try block."); } finally { // finally 블록이 실행되었음을 보여주고, // i의 값이 변경되지 않았음을 보여줍니다.. Console.WriteLine("\nIn the finally block in TryCast, i = {0}.\n", i); } } // Output: // In the finally block in TryCast, i = 123. // Catching the System.InvalidCastException exception triggers the finally block. // Unhandled Exception: System.InvalidCastException: Specified cast is not valid. }


16. finally에 대한 자세한 내용은 try-catch-finally를 참조하십시오.

17. C#에는 using 문도 포함(contain)됩니다.

18. 이 문은 간편한 구문(convenient syntax)에서 IDisposable 개체애 대해 비슷한 기능(similar functionality)을 제공합니다.





fixed 문


1. fixed 문은 가비지 수집기(garbage collector)에서 이동 가능한 변수(movable variable)를 재배치할 수 없도록 합니다.

2. fixed 문은 안전하지 않은 컨텍스트(an unsafe context)에서만 허용(permit)됩니다.

3. 또한 fixed는 고정 크기 버퍼(fixed size buffers)를 만드는 데 사용할 수도 있습니다.

4. fixed 문은 관리되는 변수(a managed variable)에 대한 포인터를 설정하고 문 실행 중에 해당 변수를 "고정"(pin)합니다.

5. fixed가 없으면 가비지 수집 시 변수가 예기치 않게(unpredictably) 재배치 될 수 있기 때문에 이동 가능한 관리되는 변수의 포인터는 거의 사용되지 않습니다(be of little use).

6. C# 컴파일러에서만 fixed 문에 관리되는 변수에 대한 포인터를 할당할 수 있습니다.


unsafe static void TestMethod()
{

    // Assume that the following class exists.
    //class Point 
    //{ 
    //    public int x;
    //    public int y; 
    //}

    // Variable pt is a managed variable, subject to garbage collection.
    Point pt = new Point();

    // Using fixed allows the address of pt members to be taken,
    // and "pins" pt so that it is not relocated.

    fixed (int* p = &pt.x)
    {
        *p = 1;
    }        

}


7. 배열, 문자열, 고정 크기 버퍼 또는 변수 주소를 사용하여 포인터를 초기화할 수 있습니다.

8. 다음 예제는 변수 주소, 배열, 문자열의 사용 방법을 보여줍니다.

9. 고정 크기 버퍼에 대한 자세한 내용은 고정 크기 버퍼를 참조하십시오.


static unsafe void Test2()
{
    Point point = new Point();
    double[] arr = { 0, 1.5, 2.3, 3.4, 4.0, 5.9 };
    string str = "Hello World";

    // The following two assignments are equivalent. Each assigns the address
    // of the first element in array arr to pointer p.

    // You can initialize a pointer by using an array.
    fixed (double* p = arr) { /*...*/ }

    // You can initialize a pointer by using the address of a variable. 
    fixed (double* p = &arr[0]) { /*...*/ }

    // The following assignment initializes p by using a string.
    fixed (char* p = str) { /*...*/ }

    // The following assignment is not valid, because str[0] is a char, 
    // which is a value, not a variable.
    //fixed (char* p = &str[0]) { /*...*/ } 


    // You can initialize a pointer by using the address of a variable, such
    // as point.x or arr[5].
    fixed (int* p1 = &point.x)
    {
        fixed (double* p2 = &arr[5])
        {
            // Do something with p1 and p2.
        }
    }
}


10. 포인터가 모두 같은 형식이라면 아래와 같이 여러 포인터를 초기화할 수 있습니다.


fixed (byte* ps = srcarray, pd = dstarray) {...}


11. 서로 다른 형식의 포인터를 초기화하려면 다음 예제와 같이 fixed 문을 중첩하기만 하면 됩니다.


fixed (int* p1 = &point.x)
{
    fixed (double* p2 = &arr[5])
    {
        // Do something with p1 and p2.
    }
}


12. 문의 코드가 실행된 후에는 고정된 모든 변수의 고정이 해제되어 가비지 수집 대상이 됩니다.

13. 따라서 fixed 문 밖에서 그러한 변수를 참조해서는 안 됩니다.


System_CAPS_note참고

fixed 문으로 초기화된 포인터는 수정할 수 없습니다.

14. unsafe 모드에서는 스택에 메모리를 할당할 수 있습니다.

15. 이러한 스택은 가비지 수집의 대상이 아니므로 고정할 필요가 없습니다.

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


class Point
{ 
    public int x, y; 
}

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

    unsafe static void Main() 
    {
        Point pt = new Point();
        pt.x = 5;
        pt.y = 6;
        // Pin pt in place:
        fixed (int* p = &pt.x) 
        {
            SquarePtrParam (p);
        }
        // pt now unpinned.
        Console.WriteLine ("{0} {1}", pt.x, pt.y);
    }
}
/*
Output:
25 6
 */





float


1. float 키워드는 32비트 부동 소수점 값을 저장하는 단순 형식을 나타냅니다.

2. 다음 표에서는 float 형식의 전체 자릿수와 근사 범위를 보여 줍니다.

형식

근사 범위

전체 자릿수 (Precision)

.NET Framework 형식

float

-3.4 × 1038to +3.4 × 1038

7개의 자릿수

System.Single

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

4. 따라서 float 형식의 변수를 초기화하려면 다음 예제와 같이 f 또는 F 접미사를 사용하십시요.


float x = 3.5F;


5. 위의 선언에서 접미사를 사용하지 않은 경우 float 변수에 double 값을 저장하려고 했으므로 컴파일 오류가 발생합니다.

6. 한 식에서 숫자 계열 형식과 부동 소수점 형식을 함께 사용할 수 있습니다.

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

    - 부동 소수점 형식 중 하나가 double인 경우 식은 double로 계산되거나, 관계식이거나 Boolean 식의 경우 bool로 계산됩니다. 

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

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

    - 양수 및 음수 0

    - 양수 및 음수 무한

    - NaN(Not-a-Number) 값

    - 0이 아닌 값의 유한 집합

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

10. 다음 예제에서는 수학 식(mathematical expression)에 int, short, float가 포함되고 결과는 float가 됩니다.

11. float은 System.Single 형식의 별칭이라는 것을 기억하십시오.

12. 이 식에 double 형식은 없습니다.


class FloatTest 
{
    static void Main() 
    {
        int x = 3;
        float y = 4.5f;
        short z = 5;
        var result = x * y / z;
        Console.WriteLine("The result is {0}", result);
        Type type = result.GetType();
        Console.WriteLine("result is of type {0}", type.ToString());
    }
}
/* Output: 
  The result is 2.7
  result is of type System.Single //'float' is alias for 'Single'
 */





1. for 루프를 사용해서 지정된 식이 false로 평가될 때까지 반복적으로 하나의 문을 또는 문의 블록을 실행할 수 있습니다.

2. 이 종류의 loop는 배열을 반복하고 얼마나 반복할지 미리 알고 있는 다른 응용 프로그램에 유용합니다.

3. 다음 에제에서 i의 값을 콘솔에 작성하고, loop의 각 반복마다 1식 증가합니다.


class ForLoopTest 
{
    static void Main() 
    {
        for (int i = 1; i <= 5; i++)
        {
            Console.WriteLine(i);
        }
    }
}
/*
Output:
1
2
3
4
5
*/


4. 위의 예제에서 for 문은 다음 동작을 수행(perform)합니다.

    1) 첫째, 변수 i의 초기 값이 설정됩니다.

    2) 이 단계는 루프의 반복 횟수와 관계없이 한 번만 발생합니다.

    3) 이 초기화를 반복 과정의 외부에서 발생한다고 생각할 수 있습니다.

    4) 조건 (i <=5)를 평가하기 위해서 i의 값은 5와 비교됩니다.

    5) i가 5보다 작거나 같다면, 조건은 true로 계산되고, 다음 동작이 발생합니다.

        i) 루프의 본문의 Console.WriteLine 문이 i의 값은 표시합니다.

        ii) i의 값을 1씩 증가합니다.

        iii) 루프는 조건을 다시 계산하기 위해서 2단계의 시작으로 돌아갑니다.

    6) i가 5보다 크다면 조건은 false로 계산되고 루프를 종료(exit)합니다.

5. i의 초기 값이 5보다 크면 루프의 본문은 한번도 실행되지 않습니다.

6. 모든 for 문은 이니셜라이저, 조건, 반복기 섹션을 정의합니다.


for (initializer; condition; iterator)
    body


7. 일반적으로(usually) 이러한 섹션 루프의 반복 횟수를 결정합니다.

8. 섹션은 다음과 같은 목적으로 사용됩니다.

    1) 이니셜라이저 섹션은 초기 조건을 설정합니다.

    2) 루프로 들어가기 전에 이 섹션의 문은 한 번만 실행됩니다(run).

    3) 이 섹션은 다음 두 가지 옵션중 하나만 포함할 수 있습니다.

        i) 첫 예제(int i = 1)가 보여주듯, 지역 loop 변수의 선언과 초기화, loop에서 변수는 지역적이고 loop의 외부에서 접근할 수 없습니다.

        ii) 다음 목록에서 쉼표(commas)로 구분 된 0개 이상의 문 식 

            ㄱ) 할당 문(assignment statement)

            ㄴ) 메서드 호출(invocation of a method)

            ㄷ) ++i 또는 i++과 같은 전위 또는 후위 증가 식(increment expression)

            ㄹ) --i 또는 i--와 같은 전위 또는 후위 감소 식(decrement expression)

            ㅁ) new를 사용한 객체 생성(creation of an object by using new)

            ㅂ) await 식

        iii) 루프의 본문은 하나의 문 또는 빈 문 또는 문 블록(중괄호로 0개 이상의 문을 묶는)으로 구성됩니다.

        iv) break 키워드를 사용해서 for 루프를 빠져 나올 수 있습니다(break out of).

        v) continue 키워드를 사용해서 다음 반복으로 갈 수 있습니다(step to the next iteration).

        v) goto, return, throw 문을 사용해서 어떤 루프든지 끝낼 수 있습니다.

9. 첫 번째 예제에서는 가장 일반적인 종류의 for 루프(the most typical kind of for loop)를 보여주고 다음 선택을 합니다.

    1) 이니셜라이저는 로컬 루프 변수 i를 선언하고 초기화 합니다.

    2) 루프의 반복 횟수를 유지합니다(maintaion).

    3) 조건은 알려진 최종 값 5에 대해서(against) 루프 변수의 값을 검사합니다.

    4) 반복기 섹션은 후위 증가 문(postfix increment statement) i++를 사용하여 루프의 각 반복을 셉니다.

10. 다음 에제는 일반적이지 않은 선택 사항을 보여줍니다.

    1) 이니셜라이저 섹션에서 값을 외부 루프 변수에 할당

    2) 이니셜라이저와 반복기 섹션 모두에서 Console.WriteLine 메서드 호출

    3) 반복기 섹션에서 두 변수의 값을 변경


static void Main()
 {
     int i;
     int j = 10;
     for (i = 0, Console.WriteLine("Start: {0}",i); i < j; i++, j--, Console.WriteLine("i={0}, j={1}", i, j))
     {
         // Body of the loop.
     }
 }
 // Output:
 // Start: 0
 // i=1, j=9
 // i=2, j=8
 // i=3, j=7
 // i=4, j=6
 // i=5, j=5


11. for 문을 정의하는 모든 식은 선택 사항입니다.

12. 예를 들어 다음 문은 무한 루프를 만듭니다.


for (; ; )
{
    // ... 
}





foreach, in


1. foreach 문은 배열이나 System.Collections.IEnumerable 또는 System.Collections.Generic.IEnumerable<T> 인터페이스를 구현하는 개체 컬렉션에 있는 각 요소에 대해 포함(embedded) 문 그룹을 반복하여 실행합니다.

2. foreach 문은 컬렉션을 반복(iterate through) 실행하여 원하는 정보를 얻는 용도로 사용할 수 있지만 예측할 수 없는(unpredictable) 부작용(side effects)을 방지하면서 소스 컬렉션의 항목을 추가하거나 제거하는 용도로는 사용할 수 없습니다.

3. 소스 컬렉션에서 아이템을 추가하거나 제거하려면 for 루프를 사용하세요.

4. 배열 또는 컬렉션의 각 요소에 대해 포함 문(the embedded statements)이 계속 실행됩니다.

5. 컬렉션의 모든 요소에 대해 반복이 완료된 후에는 제어가 foreach 블록 아래의 다음 문으로 전달됩니다.

6. foreach 블록의 모든 위치에서(at any point) break 키워드를 사용해서 루프를 벗어나거나 continue 키워드를 사용해서 루프의 다음 반복으로 이동할 수 있습니다.

7. foreach 루프는 또한 goto, return, throw 문을 통해서 종료될 수 있습니다.

8. foreach 키워드에 대한 자세한 내용과 코드 예제는 다음 항목(topics)을 참조하십시오.

    - 배열에 foreach 사용

    - 방법 : foreach를 사용하여 컬렉션 클래스 액세스

9. 다음 코드에서는 세 가지 에제를 보여줍니다.

    - 정수 배열의 내용을 표시하는 일반적인(typically) foreach 루프입니다.

    - 동일한 기능을 수행하는 for 루프

    - 배열에 있는 요소의 수를 유지하는 foreach 루프


class ForEachTest { static void Main(string[] args) { int[] fibarray = new int[] { 0, 1, 1, 2, 3, 5, 8, 13 }; foreach (int element in fibarray) { System.Console.WriteLine(element); } System.Console.WriteLine(); // 이전 루프를 for 루프와 비교 for (int i = 0; i < fibarray.Length; i++) { System.Console.WriteLine(fibarray[i]); } System.Console.WriteLine(); // 컬렉션에서 요소의 수를 유지할 수 있다. int count = 0; foreach (int element in fibarray) { count += 1; System.Console.WriteLine("Element #{0}: {1}", count, element); } System.Console.WriteLine("Number of elements in the array: {0}", count); } // Output: // 0 // 1 // 1 // 2 // 3 // 5 // 8 // 13 // 0 // 1 // 1 // 2 // 3 // 5 // 8 // 13 // Element #1: 0 // Element #2: 1 // Element #3: 1 // Element #4: 2 // Element #5: 3 // Element #6: 5 // Element #7: 8 // Element #8: 13 // Number of elements in the array: 8 }





goto


1. goto 문은 프로그램의 제어를 레이블 문(labeled statement)으로 직접 전달(transfer)합니다.

2. 일반적으로(common) goto는 switch 문에서 특정 switch-case 레이블이나 기본 레이블로 제어를 전달하는 데 사용합니다.

3. 다음 예제에서는 switch 문에서 goto를 사용하는 방법을 보여 줍니다(demonstrate)


class SwitchTest
{
    static void Main()
    {
        Console.WriteLine("Coffee sizes: 1=Small 2=Medium 3=Large");
        Console.Write("Please enter your selection: ");
        string s = Console.ReadLine();
        int n = int.Parse(s);
        int cost = 0;
        switch (n)
        {
            case 1:
                cost += 25;
                break;
            case 2:
                cost += 25;
                goto case 1;
            case 3:
                cost += 50;
                goto case 1;
            default:
                Console.WriteLine("Invalid selection.");
                break;
        }
        if (cost != 0)
        {
            Console.WriteLine("Please insert {0} cents.", cost);
        }
        Console.WriteLine("Thank you for your business.");

        // Keep the console open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}
/*
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.
*/

4. 아래 예제에서는 goto를 사용하여 중첩된(nested) 루프를 벗어나는 방법을 설명합니다.


public class GotoTest1
{
    static void Main()
    {
        int x = 200, y = 4;
        int count = 0;
        string[,] array = new string[x, y];

        // 배열 초기화:
        for (int i = 0; i < x; i++)

            for (int j = 0; j < y; j++)
                array[i, j] = (++count).ToString();

        // Read input:
        Console.Write("Enter the number to search for: ");

        // Input a string:
        string myNumber = Console.ReadLine();

        // Search:
        for (int i = 0; i < x; i++)
        {
            for (int j = 0; j < y; j++)
            {
                if (array[i, j].Equals(myNumber))
                {
                    goto Found;
                }
            }
        }

        Console.WriteLine("The number {0} was not found.", myNumber);
        goto Finish;

    Found:
        Console.WriteLine("The number {0} is found.", myNumber);

    Finish:
        Console.WriteLine("End of search.");


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

Sample Output
Enter the number to search for: 44
The number 44 is found.
End of search.
*/





if-else


1. else 참조




implicit


1. implicit 키워드는 암시적인(implicit) 사용자 정의 형식 변환 연산자를 선언하는 데 사용됩니다.

2. 이 키워드를 사용하면 사용자 정의 형식과 다른 형식 간의 암시적인 변환이 가능합니다.

3. 변환이 변환으로 인해 데이터가 손실(a loss of data)되지 않는 경우에 한합니다.


class Digit { public Digit(double d) { val = d; } public double val; // ...other members // Digit 에서 double로의 사용자 정의 변환 public static implicit operator double(Digit d) { return d.val; } // double에서 Digit로의 사용자 정의 변환 public static implicit operator Digit(double d) { return new Digit(d); } } class Program { static void Main(string[] args) { Digit dig = new Digit(7); //This call invokes the implicit "double" operator double num = dig; //This call invokes the implicit "Digit" operator Digit dig2 = 12; Console.WriteLine("num = {0} dig2 = {1}", num, dig2.val); Console.ReadLine(); }

}


4. 암시적 변환은 불필요한 캐스트(unnecessary casts)를 제거하여(eliminate), 소스 코드를 읽기 쉽도록(readability) 합니다.

5. 그러나 암서적 변환을 수행할 때는 프로그래머가 한 형식을 다른 형식으로 명시적으로 캐스팅할 필요가 없으므로 예기치 않은(unexpected) 결과가 발생하지 않도록 주의해야 합니다(care must be taken to V).

6. 일반적으로(In general) 프로그래머가 개입하지 않고(without the programmer's awareness) 암시적 변환 연산자를 안전하게 사용하려면 해당 연산자에서 예외를 throw하거나 정보가 손실(lose information)되지 않도록 해야 합니다.

7. 변환 연산자가 이러한 기준(those criteria)을 충족(meet)시키지 못하는 경우 연산자를 explicit로 표시(marked)해야 합니다.

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





in


1. foreach 참조




in(제네릭 한정자)


1. 제네릭 형식 매개 변수의 경우 in 키워드는 형식 매개 변수가 반공변(contravariant)임을 나타냅니다.

2. 제네릭 인터페이스와 대리자에서 in 키워드를 사용할 수 있습니다.

3. 반공변성(contravariance)을 사용하면 제네릭 매개 변수로 지정된 형식보다 더 적게 파생된 형식을 사용할 수 있습니다.

4. 이 경우 variant 인터페이스를 구현하는 클래스의 암시적 변환과 대리자 형식의 암시적 변환이 가능합니다.

5. 제네릭 형식 매개 변수의 공 분산(covariance)과 반공 분산(contravariance)은 참조 형식에만 지원되고 값 형식에는 지원되지 않습니다.

6. 형식이 메서드 인수의 형식으로만 사용되고 메서드 반환 형식으로는 사용되지 않는 경우 제네릭 인터페이스 또는 대리자에서 형식이 반공변(contravariant)으로 선언될 수 있습니다.

7. Ref 및 out 파라미터는 variant가 될 수 없습니다.

8. 반공변(contravariant) 형식 매개 변수가 있는 인터페이스의 메서드는 인터페이스 형식 매개 변수로 지정된 형식보다 더 적게 파생된 형식의 인수를 사용할 수 있습니다.

9. 예를 들어, .NET Framework 4의 IComparer<T> 인터페이스에서 형식 T는 반공변(contravariant)이므로 Employee가 Person를 상속(inherit)하는 경우 특수 변환 메서드를 사용하지 않고도 IComparer(Of Person) 형식의 개체를 IComparer(Of Employee) 형식의 개체에 할당할 수 있습니다.

10. 형식이 같고 더 적게 파생된 형식 매개 변수를 사용하는 다른 대리자에 반공변(contravariant) 대리자를 할당할 수 있습니다.

11. 자세한 내용은 공 분산 및 반공 분산을 참조하십시오.

12. 다음 예제에서는 반공변(contravariant) 제네릭 인터페이스를 선언, 확장 및 구현하는 방법을 보여줍니다.

13. 또한 이 인터페이스를 구현하는 클래스의 암시적 변환을 사용하는 방법도 보여줍니다


// Contravariant interface.
interface IContravariant<in A> { }

// Extending contravariant interface.
interface IExtContravariant<in A> : IContravariant<A> { }

// Implementing contravariant interface.
class Sample<A> : IContravariant<A> { }

class Program
{
    static void Test()
    {
        IContravariant<Object> iobj = new Sample<Object>();
        IContravariant<String> istr = new Sample<String>();

        // You can assign iobj to istr because
        // the IContravariant interface is contravariant.
        istr = iobj;
    }
}


14. 다음 예제에서는 반공변(contravariant) 제네릭 대리자를 선언, 인스턴스화 및 호출하는 방법을 보여 줍니다.

15. 또한 대리자 형식을 암시적으로 변환하는 방법도 보여 줍니다.


// Contravariant delegate.
public delegate void DContravariant<in A>(A argument);

// Methods that match the delegate signature.
public static void SampleControl(Control control)
{ }
public static void SampleButton(Button button)
{ }

public void Test()
{

    // Instantiating the delegates with the methods.
    DContravariant<Control> dControl = SampleControl;
    DContravariant<Button> dButton = SampleButton;

    // You can assign dControl to dButton
    // because the DContravariant delegate is contravariant.
    dButton = dControl;

    // Invoke the delegate.
    dButton(new Button()); 
}





int


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

형식

범위

크기

.NET Framework 형식

기본값

int

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

부호 있는 32비트 정수

System.Int32

0

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


int i = 123;


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

4. 이 예제에서 정수 리터럴의 형식은 int입니다.

5. int에서 long, float, double 또는 decimal로의 미리 정의된 암시적 변환이 있습니다.


// '123' 이 int이므로 암시적 변환이 일어납니다. float f = 123;


6. sbyte, byte, short, ushort 또는 char에서 int로의 암시적 변환이 미리 정의되어 있습니다.

7. 예를 들어 캐스트를 사용하지 않으면(without a cast) 다음 대입문(the following assignment statement)에서 컴파일 오류가 발생합니다(produce a compilation error).


long aLong = 22;
int i1 = aLong;       // Error: no implicit conversion from long.
int i2 = (int)aLong;  // OK: explicit conversion.


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

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


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


10. 부동 소수점 형식 및 정수 계열 형식이 함께 사용되는 산술식(arithmetic expressions)에 대한 자세한 내용은 float 및 double를 참조하십시오.





interface


1. 인터페이스에는 메서드, 속성(properties), 이벤트, 인덱서의 시그니처만 포합됩니다.

2. 인터페이스를 구현하는 클래스나 구조체는 인터페이스의 정의(definition)에 지정된 인터페이스 멤버를 구현해야 합니다.

3. 다음 예제에서는 ImplementationClass 클래스가 매개 변수를 사용하지 않고 void를 반환하는 SampleMethod 메서드를 구현해야 합니다.

4. 자세한 내용과 예제를 보려면 인터페이스를 참조하십시오.


interface ISampleInterface { void SampleMethod(); } class ImplementationClass : ISampleInterface { // 명시적 인터페이스 멤버 구현: void ISampleInterface.SampleMethod() { // 메서드 구현 } static void Main() { // 인터페이스 인스턴스 선언. ISampleInterface obj = new ImplementationClass(); // 멤버 호출. obj.SampleMethod(); } }


5. 인터페이스는 네임스페이스 또는 클래스의 멤버가 될 수 있으며 다음 멤버의 시그니처를 포함할 수 있습니다.

    - 메서드, 속성, 인덱서, 이벤트

6. 인터페이스는 하나 이상의 기본 인터페이스(base interfaces)에서 상속할 수 있습니다.

7. 기본 형식 목록에 기본 클래스와 인터페이스가 있는 경우 기본 클래스가 목록의 처음에 있어야 합니다.

8. 인터페이스를 구현하는 클래스는 해당 인터페이스의 멤버를 명시적으로 구현할 수 있습니다.

9. 명시적으로 구현된 멤버는 클래스 인스턴스를 통해 액세스할 수 없고 인터페이스의 인스턴스를 통해서만 액세스할 수 있습니다.

10. 명시적 인터페이스 구현에 대한 자세한 내용과 코드 예제는 명시적 인터페이스 구현을 참조하십시오.

11. 다음 예제에서는 인터페이스 구현  방법을 보여 줍니다(demonstrate).

12. 이 예제에서 인터페이스에는 속성 선언이 포함되고 클래스에는 구현이 포함됩니다.

13. IPoint를 구현하는 클래스 인스턴스에 정수 속성(integer properties) x 및 y가 있습니다.


interface IPoint { // 속성 시그니처: int x { get; set; } int y { get; set; } } class Point : IPoint { // 필드: private int _x; private int _y; // 생성자: public Point(int x, int y) { _x = x; _y = y; } // 속성 구현: public int x { get { return _x; } set { _x = value; } } public int y { get { return _y; } set { _y = value; } } } class MainClass { static void PrintPoint(IPoint p) { Console.WriteLine("x={0}, y={1}", p.x, p.y); } static void Main() { Point p = new Point(2, 3); Console.Write("My Point: "); PrintPoint(p); } } // Output: My Point: x=2, y=3






internal


1. internal 키워드는 형식 및 형식 멤버에 대한 액세스 한정자(access modifier) 입니다.

2;. internal 타입이나 멤버는 다음 예제와 같이 동일한 어셈블리의 파일 내에서만 액세스할 수 있습니다.


public class BaseClass 
{
    // Only accessible within the same assembly
    internal static int x = 0;
}


3. 액세스 한정자 protected internal이 있는 형식이나 멤버는 현재 어셈블리 또는 포함하는 클래스에서 파생된 형식에서 액세스할 수 있습니다.

4. internal을 다른 액세스 한정자와 비교하려면 액세스 가능성 수준액세스 한정자를 참조하십시오.

5. 어셈블리에 대한 자세한 내용은 어셈블리와 전역 어셈블리 캐시를 참조하십시오.

6. 내부 액세스는 구성 요소 그룹이 나머지 응용 프로그램 코드(the rest of the application code)에 노출(exposed)되지 않으면서 상호 작용할 수(cooperate in a private manner) 있도록 하기 때문에 구성 요소 기반 개발(component-based development)에 주로 사용됩니다.

7. 예를 들어 그래픽 사용자 인터페이스를 빌드하기 위한 프레임워크는 내부 액세스가 지정된 멤버를 사용하여 상호 작용하는 Control 및 Form 클래스를 제공할 수 있습니다.

8. 이 멤버들은 내부 멤버이기 때문에 프레임워크를 사용하는 코드에 노출되지 않습니다.

9. 내부 액세스 형식 또는 멤버를 해당 형식 또는 멤버가 정의된 어셈블리 외부에서 참조(reference)하면 오류가 발생합니다.

10. 다음 예제에서는 두 개의 파일 Assembly1.cs 및 Assembly1_a.cs가 포함되어 있습니다.

11. 첫 번째 파일에는 내부 기본 클래스 BaseClass가 있습니다.

12. 두 번째 파일에서 BaseClass를 인스턴스화하려고 시도하면 오류가 발생합니다.


// Assembly1.cs
// Compile with: /target:library
internal class BaseClass 
{
   public static int intM = 0;
}


// Assembly1_a.cs
// Compile with: /reference:Assembly1.dll
class TestAccess 
{
   static void Main() 
   {
      BaseClass myBase = new BaseClass();   // CS0122
   }
}


13. 다음 예제에서는 예제 1에 사용한 것과 같은 파일을 사용하되 BaseClass의 액세스 수준(the accessibility level)을 public으로 변경합니다.

14. 또한 IntM 멤버의 액세스 수준을 internal로 변경합니다.

15. 이 경우 클래스를 인스턴스화할 수는 있지만 내부 멤버에 액세스할 수는 없습니다.


// Assembly2.cs
// Compile with: /target:library
public class BaseClass 
{
   internal static int intM = 0;
}


// Assembly2_a.cs
// Compile with: /reference:Assembly1.dll
public class TestAccess 
{
   static void Main() 
   {
      BaseClass myBase = new BaseClass();   // Ok.
      BaseClass.intM = 444;    // CS0117
   }
}





is


1. 지정된 형식(a given type)과 개체가 호환되는지(compatible with) 검사합니다(check).

2. 예를 들어 다음 코드에서는 개체가 MyObject 형식의 인스턴스이거나 MyObject에서 파생 형식인지 확인할(determine) 수 있습니다.


if (obj is MyObject)
{
}


3. 지정된 식이 null이 아니고(non-null) 예외를 throw하지 않은 채 지정된 개체를 지정된 형식으로 캐스팅할 수 있는 경우 is 식은 true가 됩니다.

4. 식이 항상 true이거나 항상 false인 것으로 알려져 있는 경우 is 키워드는 컴파일 타임 경고를 발생시키지만 런타임에는 일반적으로(typically) 형식 호환성을 확인합니다.

5. is 연산자는 오버로드되지 않습니다.

6. is 연산자는 참조 변환, boxing 변환 및 unboxing 변환만 고려합니다.

7. 사용자 정의 변환 같은 다른 변환은 고려되지 않습니다.

8. 무명 메서드는 is 연산자의 왼쪽에 사용할 수 없습니다.

9. 이 예외에는 lambda 식이 포함됩니다.


class Class1 {}
class Class2 {}
class Class3 : Class2 { }

class IsTest
{
    static void Test(object o)
    {
        Class1 a;
        Class2 b;

        if (o is Class1)
        {
            Console.WriteLine("o is Class1");
            a = (Class1)o;
            // Do something with "a."
        }
        else if (o is Class2)
        {
            Console.WriteLine("o is Class2");
            b = (Class2)o;
            // Do something with "b."
        }
        else
        {
            Console.WriteLine("o is neither Class1 nor Class2.");
        }
    }
    static void Main()
    {
        Class1 c1 = new Class1();
        Class2 c2 = new Class2();
        Class3 c3 = new Class3();
        Test(c1);
        Test(c2);
        Test(c3);
        Test("a string");
    }
}
/*
Output:
o is Class1
o is Class2
o is Class2
o is neither Class1 nor Class2.
*/





lock


1. lock 키워드는 지정된 객체를 상호 배타적(mutual-exclusion)으로 잠그고 문을 실행한 다음 잠금을 해제함으로써 문 블럭을 임계 영역(critical section)으로 표시합니다.

2. 다음 예제에서는 lock 문을 포함합니다.


class Account
{
    decimal balance;
    private Object thisLock = new Object();

    public void Withdraw(decimal amount)
    {
        lock (thisLock)
        {
            if (amount > balance)
            {
                throw new Exception("Insufficient funds");
            }
            balance -= amount;
        }
    }
}


3. 자세한 내용은 스레드 동기화를 참조하십시오.

4. lock 키워드를 사용하면 다른 스레드가 코드의 임계 영역에 있는 동안에는 특정 스레드가 임계 영역에 들어갈 수 없습니다.

5. 다른 스레드가 잠긴 코드에 들어가려고 할 경우 개체가 해제(release)될 때까지 대기합니다.

6. 스레딩에 대한 자세한 내용은 스레딩 단원을 참조하십시오.

7. lock 키워드는 블록의 시작 부분에서 Enter를 호출하고 블록의 끝 부분에서 Exit를 호출합니다.

8. 인터럽트가 lock 문에 들아가려고 대기하고 있는 스레드에 인터럽트 한다면 ThreadInterruptedException 가 throw됩니다.

9. 일반적으로 코드에서 제어되지 않는 인스턴스나 public 형식은 잠그지 않는 것이 좋습니다.

10. 일반적인 구문)constructs) lock (this), lock (typeof (MyType)) 및 lock("myLock")은 다음과 같이 이 지침을 위반합니다.

    1) lock (this) - 해당 인스턴스에 공용으로 액세스할 수 있는 경우 문제가 됩니다.

    2) lock (typeof (MyType)) - MyType에 공용으로 액세스할 수 있는 경우 문제가 됩니다.

    3) lock("myLock") - 동일한 문자열을 사용하는 프로세스의 다른 코드가 동일한 잠금을 공유하게 되므로 문제가 됩니다.

11. 가장 좋은 방법(Best practice)은 private 개체를 정의하여 잠그거나 private static 개체 변수를 정의하여 모든 인스턴스에 공통된(common) 데이터를 보호하는 것입니다.

12. lock 문의 본문에 await 키워드를 사용할 수 없습니다.

13. 다음 샘플에서는 C#에서 잠금 없이 스레드를 사용하는 간단한 방법을 보여줍니다.


//using System.Threading;

class ThreadTest
{
    public void RunMe()
    {
        Console.WriteLine("RunMe called");
    }

    static void Main()
    {
        ThreadTest b = new ThreadTest();
        Thread t = new Thread(b.RunMe);
        t.Start();
    }
}
// Output: RunMe called


14. 다음 샘플에서는 스레드와 lock을 사용합니다.

15. lock 문이 있으면(is present), 문 블록이 임계 영역이 되고 balance는 음수(a negative number)가 되지 않습니다.


// using System.Threading;

class Account
{
    private Object thisLock = new Object();
    int balance;

    Random r = new Random();

    public Account(int initial)
    {
        balance = initial;
    }

    int Withdraw(int amount)
    {

        // This condition never is true unless the lock statement
        // is commented out.
        if (balance < 0)
        {
            throw new Exception("Negative Balance");
        }

        // Comment out the next line to see the effect of leaving out 
        // the lock keyword.
        lock (thisLock)
        {
            if (balance >= amount)
            {
                Console.WriteLine("Balance before Withdrawal :  " + balance);
                Console.WriteLine("Amount to Withdraw        : -" + amount);
                balance = balance - amount;
                Console.WriteLine("Balance after Withdrawal  :  " + balance);
                return amount;
            }
            else
            {
                return 0; // transaction rejected
            }
        }
    }

    public void DoTransactions()
    {
        for (int i = 0; i < 100; i++)
        {
            Withdraw(r.Next(1, 100));
        }
    }
}

class Test
{
    static void Main()
    {
        Thread[] threads = new Thread[10];
        Account acc = new Account(1000);
        for (int i = 0; i < 10; i++)
        {
            Thread t = new Thread(new ThreadStart(acc.DoTransactions));
            threads[i] = t;
        }
        for (int i = 0; i < 10; i++)
        {
            threads[i].Start();
        }
    }
}

 



long


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

형식

범위

크기

.NET Framework 형식

long

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

부호 있는 64비트 정수

System.Int64

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


long long1 = 4294967296;


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

4. 앞의 예에서 정수 리터럴의 형식은 uint 범위를 초과하기 때문에 long입니다.

5. 정수 게열 형식의 저장  크기에 대해서는 정수 계열 형식 표를 참조하십시오.

6. 또한 다음과 같이 long 형식에 L 접미사를 사용할 수도 있습니다.


long long2 = 4294967296L;


7. L 접미사를 사용할 경우 리터럴 형식은 크기에 따라 long 또는 ulong으로 결정됩니다.

8. 위의 경우 리터럴 정수는 ulong 범위보다 작기 때문에 long 형식입니다.

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

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


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


11. 이 경우, L 접미사를 사용하면 올바른 형식이 호출됩니다.


SampleMethod(5);    // Calling the method with the int parameter
SampleMethod(5L);   // Calling the method with the long parameter


12. 같은 식에서 다른 숫자 정수 계열 형식과 함께 long 형식을 사용할 수 있습니다.

13. 이런 경우  long으로 계산되고 부울 식 또는 관계식의 경우에는 bool로 계산됩니다.

14. 예를 들어 다음 식은 long으로 계산됩니다.


898L + 88


System_CAPS_note참고

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

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

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

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

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


int x = 8L;        // Error: no implicit conversion from long to int
int x = (int)8L;   // OK: explicit conversion to int


19. sbyte, byte, short, ushort, int, uint 또는 char에서 long으로의 암시적 변환이 미리 정의되어 있습니다.

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

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


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





namespace


1. namespace 키워드를 사용하여 관련된 개체 집합이 포함된 범위를 선언합니다.

2. 네임스페이스 코드 요소를 구성하고 전역적으로 고유한 형식(globally unique types)을 만들 수 있습니다.


namespace SampleNamespace
{
    class SampleClass { }

    interface SampleInterface { }

    struct SampleStruct { }

    enum SampleEnum { a, b }

    delegate void SampleDelegate(int i);

    namespace SampleNamespace.Nested
    {
        class SampleClass2 { }
    }
}


3. 네임스페이스 내에서 아래와 같은 형식을 하나 이상 선언할 수 있습니다.

    1) 기타 네임스페이스(another namespace)

    2) class

    3) interface

    4) struct

    5) enum

    6) 대리자(delegate)


4. C# 소스 파일에 네임스페이스를 명시적으로 선언하든 그렇지 않든 관계없이 컴파일러에서는 기본 네임스페이스를 추가합니다.

5. 명명되지 않은 이 네임스페이스는 전역 네임스페이스라고도 하며 모든 파일에 존재합니다(is present).

6. 전역 네임스페이스(global namespace)의 모든 식별자(Any identifier)는 명명된 네임스페이스에서 사용할 수 있습니다.

7. 네임스페이스는 암시적으로(implicitly) 공용 액세스이며 수정할 수는 없습니다(is not modifiable).

8. 네임스페이스의 요소에 할당할 수 있는 액세스 한정자에 대한 자세한 내용은 액세스 한정자를 참조하십시오.

9. 두 개 이상의 선언에서 네임스페이스를 정의할 수 있습니다.

10. 예를 들어, 다음 예제에서는 두 클래스를 모두 MyCompany 네임스페이스의 일부로 정의합니다.


namespace MyCompany.Proj1
{
    class MyClass
    {
    }
}

namespace MyCompany.Proj1
{
    class MyClass1
    {
    }
}


11. 아래 예제에서는 중첩된 네임스페이스에서 정적 메서드를 호출하는 방법을 보여줍니다.


namespace SomeNameSpace
{
    public class MyClass 
    {
        static void Main() 
        {
            Nested.NestedNameSpaceClass.SayHello();
        }
    }

    // a nested namespace
    namespace Nested   
    {
        public class NestedNameSpaceClass 
        {
            public static void SayHello() 
            {
                Console.WriteLine("Hello");
            }
        }
    }
}
// Output: Hello


12. 네임스페이스 사용에 대한 자세한 내용은 다음 항복을 참조하십시오.

    1) 네임스페이스

    2) 네임스페이스 사용

    3) 방법: 전역 네임스페이스 별칭 사용





new 연산자


1. 개체를 만들고 생성자를 호출하는 데 사용됩니다.


Class1 obj  = new Class1();


2. 이는 익명 형식의 인스턴스를 만드는 데도 사용됩니다.


var query = from cust in customers
            select new {Name = cust.Name, Address = cust.PrimaryAddress};


3. 또한 new 연산자는 값 형식에 대한 기본 생성자를 호출하는 데도 사용됩니다.


int i = new int();


4. 앞의 문에서 i는 int 형식의 기본값인 0으로 초기화됩니다.

5. 앞의 문의 결과는 다음 문의 결과와 같습니다.


int i = 0;


6. 기본값의 전체 목록을 보려면 기본값 표를 참조하십시오.

7. 모든 값 형식에는 암시적으로 공용 기본 생성자(a public default constructor)가 포함되기 때문에 구조체에 대한 기본 생성자를 선언하면 오류가 발생합니다.

8. 구조체 형식에 대해 매개변수가 있는 생성자(parameterized constructors)를 선언하여 그 초기 값을 설정할 수 있지만 이 방법은 기본값이 아닌 다른 값이 필요한 경우에만 사용해야 합니다.

9. 구조체와 같은 값 형식 개체는 스택에 만들어지고 클래스 같은  참조 형식 개체는 에 만들어집니다.

10. 두 형식의 개체는 모두 자동으로 소멸됩니다.

11. 두 형식의 개체는 모두 자동으로 소멸됩니다.

12. 그러나 값 형식을 기반으로 한 개체는 범위를 벗어날 때 소멸되는 반면 참조 형식을 기반으로 한 개체는이에 대한 마지막 참조를 제거한 후에 지정되지 않은 임의의 시간에(at an unspecified time) 소멸된다는점에서 차이가 있습니다.

13. 많은 용량의 메모리, 파일 핸들 또는 네트워크 연결 같은 고정된 리소스 사용하는 참조 형식의 경우 개체가 가능한 한 빨리 소멸되도록 명확한 종료 방식(deterministic finalization)을 사용하(employ)는 것이 좋을 수도 있습니다.

14. new 연산자는 오버로드되지 않습니다.

15. new 연산자가 메모리 할당에 실패하면 OutOfMemoryException 예외를 throw합니다.

16. 다음 예제에서는 new 연산자를 사용하여 struct 개체 및 클래스 개체를 만들어 초기화한 다음 값을 대입합니다.

17. 그러면 기본값과 할당된 값이 표시됩니다.


struct SampleStruct
{
   public int x;
   public int y;

   public SampleStruct(int x, int y)
   {
      this.x = x;
      this.y = y;
   }
}

class SampleClass
{
   public string name;
   public int id;

   public SampleClass() {}

   public SampleClass(int id, string name)
   {
      this.id = id;
      this.name = name;
   }
}

class ProgramClass
{
   static void Main()
   {
      // Create objects using default constructors:
      SampleStruct Location1 = new SampleStruct();
      SampleClass Employee1 = new SampleClass();

      // Display values:
      Console.WriteLine("Default values:");
      Console.WriteLine("   Struct members: {0}, {1}",
             Location1.x, Location1.y);
      Console.WriteLine("   Class members: {0}, {1}",
             Employee1.name, Employee1.id);

      // Create objects using parameterized constructors:
      SampleStruct Location2 = new SampleStruct(10, 20);
      SampleClass Employee2 = new SampleClass(1234, "Cristina Potra");

      // Display values:
      Console.WriteLine("Assigned values:");
      Console.WriteLine("   Struct members: {0}, {1}",
             Location2.x, Location2.y);
      Console.WriteLine("   Class members: {0}, {1}",
             Employee2.name, Employee2.id);
   }
}
/*
Output:
Default values:
   Struct members: 0, 0
   Class members: , 0
Assigned values:
   Struct members: 10, 20
   Class members: Cristina Potra, 1234
*/


18. 이 예제에서 문자열의 기본값은 null입니다.

19. 따라서 값이 표시되지 않습니다.





new 한정자


1. 선언 한정자(declaration modifier) 사용되는 new 키워드는 기본 클래스에서 상속된 멤버를 명시적으로 숨깁니다.

2. 상속된 멤버를 숨기면 파생 버전의 멤버로 기본 클래스 버전의 멤버를 대신하게 됩니다.

3. new 한정자를 사용하지 않고 멤버를 숨길 수도 있지만 컴파일러 경고가 발생합니다.

4. new를 사용하여 멤버를 명시적으로 숨기면 이 경고가 발생하지 않습니다(suppress).

5. 상속된 멤버(an inherited member)를 숨기려면, 멤버 이름을 사용하여 파생된 클래스에 해당 멤버를 선언한 다음 new 키워드를 사용하여 이를 한정합니다.


public class BaseC
{
    public int x;
    public void Invoke() { }
}
public class DerivedC : BaseC
{
    new public void Invoke() { }
}


6. 이 예제에서 BaseC.Invoke는 DerivedC.Invoke에 의해 숨겨집니다.

7. x 필드는 비슷한 이름으로 숨겨져 있지 않기 때문에 영향을 받지 않습니다.

8. 상속(inheritance)을 사용한 이름 숨기기는 다음 중 한 가지 형식을 취합니다(take).

    1) 일반적으로 클래스 또는 구조체에 파생된 상수 필드, 속성 또는 형식은 동일한 이름의 모든 기본 클래스 멤버를 숨깁니다.

        이 사항이 적용되지 않는 경우가 있습니다.

        예를 들어 호출할 수 없는 형식이 포함된 N이라는 이름의 새 필드를 선언하고 기본 형식에서 N을 메서드로 선언하면 새 필드가 호출 구문에서(in invocation syntax) 기본 선언을 숨기지 않습니다.

       자세한 내용은 C# 언어 사양(C# language specification)("식" 단원의 "멤버 조회(Member Lookup)" 단원 참조)을 참조하세요.

    2) 클래스 또는 구조체에 파생된 메서드는 기본 클래스에서 동일한 이름의 속성, 필드 및 형식을 숨깁니다.

       또한 시그니처가 동일한 기본 클래스 메서드도 모두 숨깁니다.

    3) 클래스 또는 구조체에 파생된 인덱서는 시그니처가 동일한 기본 클래스 인덱서를 모두 숨깁니다.

9. 동일한 멤버에 대해 new와 override를 모두 사용하면 오류가 발생합니다.

10. 두 한정자는 함께 사용할 수 없는 의미(mutually exclusive meanings)를 지니고 있기 때문입니다.

11. new 한정자는 동일한 이름의 새 멤버를 만들고 원래 멤버를 숨깁니다.

12. override 한정자는 상속된 멤버에 대한 구현을 확장(extends the implementation)합니다.

13. 상속된 멤버를 숨기지 않는 선언에 new 한정자를 사용하면 경고가 발생합니다.

14. 이 예제에서 기본 클래스 BaseC 및 파생 클래스 DerivedC는 동일한 필드 이름 x를 사용하므로 상속된 필드의 값이 숨겨집니다.

15. 이 예제에서는 new 한정자의 사용법을 보여 줍니다.

16. 또한 정규화된 이름(fully qualified names)을 사용하여 기본 클래스의 숨겨진 멤버에 액세스하는 방법을 보여 줍니다.


public class BaseC
{
    public static int x = 55;
    public static int y = 22;
}

public class DerivedC : BaseC
{
    // Hide field 'x'.
    new public static int x = 100;

    static void Main()
    {
        // Display the new value of x:
        Console.WriteLine(x);

        // Display the hidden value of x:
        Console.WriteLine(BaseC.x);

        // Display the unhidden member y:
        Console.WriteLine(y);
    }
}
/*
Output:
100
55
22
*/


17. 이 예제에서 중첩 클래스는 기본 클래스에서 이름이 동일한 클래스를 숨깁니다.

18. 이 예제에서는 new 한정자를 사용하여 경고 메시지를 제거하는 방법과 정규화된 이름을 사용하여 숨겨진 클래스 멤버에 액세스하는 방법을 보여 줍니다.


public class BaseC 
{
    public class NestedC 
    {
        public int x = 200;
        public int y;
    }
}

public class DerivedC : BaseC 
{
    // Nested type hiding the base type members.
    new public class NestedC   
    {
        public int x = 100;
        public int y; 
        public int z;
    }

    static void Main() 
    {
        // Creating an object from the overlapping class:
        NestedC c1  = new NestedC();

        // Creating an object from the hidden class:
        BaseC.NestedC c2 = new BaseC.NestedC();

        Console.WriteLine(c1.x);
        Console.WriteLine(c2.x);   
    }
}
/*
Output:
100
200
*/


19. new 한정자를 제거해도 프로그램은 컴파일되고 실행되지만 다음과 같은 경고가 발생합니다.


The keyword new is required on 'MyDerivedC.x' because it hides inherited member 'MyBaseC.x'.





new 제약 조건


1. new 제약 조건(constraint)은 제네릭 클래스 선언의 모든 형식 인수가 매개 변수 없는 public 생성자(a public parameterless constructor)를 갖도록 지정합니다.

2. new 제약 조건을 사용하려면 형식이 abstract일 수 없습니다.

3. 다음 예제에서와 같이 제네릭 클래스로 형식의 새 인스턴스를 만들 때 형식 매개 변수에 new 제약 조건을 적용합니다.


class ItemFactory<T> where T : new()
{
    public T GetNewItem()
    {
        return new T();
    }
}

4. 다른 제약 조건과 함께 new() 제약 조건을 사용하는 경우 이 제약 조건은 마지막에 지정해야 합니다.


public class ItemFactory2<T>
    where T : IComparable, new()
{
}

5. 자세한 내용은 형식 매개 변수에 대한 제약 조건을 참조하십시오.





null


1. null 키워드는 아무 개체도 참조하지 않는 null 참조를 나타내는 리터럴입니다.

2. null은 참조 형식 변수의 기본값입니다.

3. 일반 값 형식(Ordinary value types)은 null일 수 없습니다.

4. 하지만(however), C# 2.0에는 nullable 값 형식이 도입되었습니다.

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

6. 다음 예제에서는 null 키워드의 몇 가지 동작(some behaviors)을 보여줍니다.



class Program
{
    class MyClass
    {
        public void MyMethod() { }
    }

    static void Main(string[] args)
    {
        // Set a breakpoint here to see that mc = null.
        // However, the compiler considers it "unassigned."
        // and generates a compiler error if you try to
        // use the variable.
        MyClass mc;

        // Now the variable can be used, but...
        mc = null;

        // ... a method call on a null object raises 
        // a run-time NullReferenceException.
        // Uncomment the following line to see for yourself.
        // mc.MyMethod();

        // Now mc has a value.
        mc = new MyClass();

        // You can call its method.
        mc.MyMethod();

        // Set mc to null again. The object it referenced
        // is no longer accessible and can now be garbage-collected.
        mc = null;

        // A null string is not the same as an empty string.
        string s = null;
        string t = String.Empty; // Logically the same as ""

        // Equals applied to any null object returns false.
        bool b = (t.Equals(s));
        Console.WriteLine(b);

        // Equality operator also returns false when one
        // operand is null.
        Console.WriteLine("Empty string {0} null string", s == t ? "equals": "does not equal");

        // Returns true.
        Console.WriteLine("null == null is {0}", null == null);


        // A value type cannot be null
        // int i = null; // Compiler error!

        // Use a nullable value type instead:
        int? i = null;

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

    }
}


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

C# 키워드 T~Z  (0) 2016.06.03
C# 키워드 O~S  (0) 2016.05.31
C# 키워드 A-E  (0) 2016.05.13
연산자 2  (0) 2016.05.10
C# 총정리  (0) 2016.04.19
:
Posted by 지훈2
2016. 5. 13. 15:23

C# 키워드 A-E 프로그래밍/C#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.


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

C# 키워드 O~S  (0) 2016.05.31
C# 키워드 F~N  (0) 2016.05.21
연산자 2  (0) 2016.05.10
C# 총정리  (0) 2016.04.19
정리  (0) 2016.04.09
:
Posted by 지훈2