2016년 2월 25일 목요일

C# 프로그래밍 가이드 중 일부 발췌 - Main(), 네임스페이스, nullable, 문, 식, 연산자

개인적인 copy & paste 정리입니다. 글을 보시기 보다는 아래 링크에 방문하세요.

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

Main()

https://msdn.microsoft.com/ko-kr/library/acy3edy3.aspx
C# 프로그램에는 진입점이 하나만 있을 수 있습니다. Main 메서드가 있는 클래스가 두 개 이상 있는 경우 /main 컴파일러 옵션을 통해 진입점으로 사용할 Main 메서드를 지정하여 프로그램을 컴파일해야 합니다. 자세한 내용은 /main (C# Compiler Options)을 참조하십시오.
class TestClass
{
    static void Main(string[] args)
    {
        // Display the number of command line arguments:
        System.Console.WriteLine(args.Length);
    }
}

  • Main 메서드는 프로그램 제어가 시작되고 끝나는 .exe 프로그램의 진입점입니다.
  • Main 은 클래스 또는 구조체 내부에 선언됩니다 Main 정적이어야 하며 공용이어서는 안됩니다. 이전 예제에서 이 메서드에는 기본 액세스 수준인 private이 지정되었습니다. 이 메서드의 바깥쪽 클래스나 구조체는 정적일 필요가 없습니다.
  • Main void 또는 int 반환 형식일 수 있습니다.
  • Main 메서드는 명령줄 인수를 포함하는 string[] 매개 변수가 있거나 없는 상태로 선언할 수 있습니다. Visual Studio를 사용하여 Windows Forms 응용 프로그램을 만드는 경우 수동으로 매개 변수를 추가하거나 Environment 클래스를 사용하여 명령줄 인수를 가져올 수 있습니다. 매개 변수 인덱스 0 명령줄 인수로 읽혀집니다. C 및 c + +와 달리 프로그램의 이름은 첫 번째 명령줄 인수로 처리 되지 않습니다.

네임스페이스

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

namespace SampleNamespace
{
    class SampleClass
    {
        public void SampleMethod()
        {
            System.Console.WriteLine(
              "SampleMethod inside SampleNamespace");
        }
    }
}


네임스페이스에는 다음과 같은 속성이 있습니다.
  • 큰 코드 프로젝트를 조직화합니다.
  • . 연산자로 구분됩니다.
  • using directive 를 사용하면 모든 클래스에 대해 네임스페이스의 이름을 지정할 필요가 없습니다.
  • global 네임스페이스는 "루트" 네임스페이스입니다. global::System은 항상 .NET Framework 네임스페이스인 System을 참조합니다.
https://msdn.microsoft.com/ko-kr/library/dfb3cx8s.aspx

using 지시문(C# 참조) 을 사용하여 네임스페이스의 별칭을 만들 수도 있습니다. 예를 들어, 중첩된 네임스페이스가 들어 있는 이전에 작성된 네임스페이스를 사용하는 경우 다음 예제와 같이 특정 네임스페이스를 간단하게 참조할 수 있도록 별칭을 선언할 수 있습니다.
using Co = Company.Proj.Nested;  // define an alias to represent a namespace
일반적으로 ::을 사용하여 네임스페이스 별칭을 참조하거나 global::을 사용하여 전역 네임스페이스를 참조하고 .을 사용하여 형식이나 멤버를 한정합니다.
네임스페이스 대신 형식을 참조하는 별칭과 함께 ::을 사용하면 오류가 발생합니다. 예를 들면 다음과 같습니다.

using Alias = System.Console;


class TestClass
{
    static void Main()
    {
        // Error
        //Alias::WriteLine("Hi");

        // OK
        Alias.WriteLine("Hi");
    }
}



global 이라는 단어는 미리 정의된 별칭이 아니라는 점에 주의해야 합니다. 따라서 global.X에는 특별한 의미가 없습니다. 이는 ::과 함께 사용할 때만 특별한 의미를 갖습니다.
global:: 은 항상 전역 네임스페이스를 참조하며 별칭이 아니므로 global이라는 별칭을 정의하면 컴파일러 경고 CS0440이 발생합니다. 예를 들어, 다음과 같은 줄을 사용하면 경고가 발생합니다.
using global = System.Collections;   // Warning

nullable


https://msdn.microsoft.com/ko-kr/library/1t3y8s4s.aspx
nullable 형식은 System.Nullable<T> 구조체의 인스턴스입니다. nullable 형식은 내부 값 형식의 올바른 값 범위뿐 아니라 null 값도 나타낼 수 있습니다. 예를 들어 Nullable<Int32>("Int32의 nullable"이라고 읽음)에는 -2147483648에서 2147483647까지의 모든 값을 할당하거나 null 값을 할당할 수 있습니다. Nullable<bool>에는 true, false 또는 null 값을 할당할 수 있습니다. 숫자 및 부울 형식에 null 값을 할당할 수 있는 기능은 특히 값이 할당되지 않을 수 있는 요소를 포함하는 데이터베이스 및 기타 데이터 형식을 다룰 때 유용합니다. 예를 들어 데이터베이스의 Boolean 필드는 true 또는 false 값을 저장할 수도 있고, 정의되지 않을 수도 있습니다.
class NullableExample
{
    static void Main()
    {
        int? num = null;

        // Is the HasValue property true?
        if (num.HasValue)
        {
            System.Console.WriteLine("num = " + num.Value);
        }
        else
        {
            System.Console.WriteLine("num = Null");
        }

        // y is set to zero
        int y = num.GetValueOrDefault();

        // num.Value throws an InvalidOperationException if num.HasValue is false
        try
        {
            y = num.Value;
        }
        catch (System.InvalidOperationException e)
        {
            System.Console.WriteLine(e.Message);
        }
    }
}
이 예제는 다음 출력을 표시합니다.
num = Null
Nullable object must have a value.

nullable 형식에는 다음과 같은 특징이 있습니다.
  • nullable 형식은 null 값을 할당할 수 있는 값 형식 변수를 나타냅니다. 참조 형식을 기반으로 nullable 형식을 만들 수는 없습니다. 참조 형식에서는 이미 null 값을 지원합니다.
  • T? 구문은 Nullable<T>의 축약형이고, 여기서 T는 값 형식입니다. 이러한 두 가지 형태는 서로 바꿔 사용할 수 있습니다.
  • nullable 형식에는 일반 값 형식과 같은 방법으로 값을 할당합니다. 예를 들면 int? x = 10; 또는 double? d = 4.108과 같습니다.Nullable 형식은 null: int? x = null. 값을 할당할 수도 있습니다.
  • Nullable<T>.GetValueOrDefault 메서드를 사용하여 할당된 값을 반환하거나 값이 null인 경우 내부 형식의 기본값을 반환합니다. 예를 들면 int j = x.GetValueOrDefault();와 같습니다.
  • HasValue  Value 읽기 전용 속성을 사용하여 Null에 대해 테스트하고 값을 검색합니다(예제 if(x.HasValue) j = x.Value; 참조).
    • HasValue 속성은 변수에 값이 포함되어 있을 경우 true를 반환하고, 변수가 null이면 false를 반환합니다.
    • 할당된 값이 있으면 Value 속성은 값을 반환합니다. 그렇지 않으면 System.InvalidOperationException이 throw됩니다.
    • HasValue의 기본값은 false입니다. Value 속성에는 기본값이 없습니다.
    • == and != 연산자를 Nullable 형식으로 사용할 수도 있습니다(예제 if (x != null) y = x; 참조).
  • ?? 연산자를 사용하여 현재 값이 null인 nullable 형식을 nullable이 아닌 형식에 할당할 때 적용될 기본값을 할당합니다. 예를 들면 int? x = null; int y = x ?? -1;과 같습니다.
  • 중첩된 nullable 형식은 허용되지 않습니다. Nullable<Nullable<int>> n;과 같은 줄은 컴파일되지 않습니다.
https://msdn.microsoft.com/ko-kr/library/2cf62fcy.aspx
System.Nullable<T> variable
또는
T? variable
T는 nullable 형식의 기본 형식입니다. T struct를 포함한 모든 값 형식이 될 수 있으며 참조 형식은 될 수 없습니다.
nullable 형식이 필요한 경우를 예로 들면, true와 false라는 두 가지 값만 갖는 일반적인 부울 변수를 생각해 볼 수 있습니다. 이런 변수에는 "정의되지 않은 상태"를 의미하는 값이 없습니다. 여러 프로그래밍 응용 프로그램에서 변수는 정의되지 않은 상태로 나타날 수 있으며, 데이터베이스 상호 작용이 가장 대표적인 예입니다. 예를 들어, 데이터베이스의 필드는 true나 false 값을 포함할 수 있지만 값을 전혀 포함하지 않을 수 있습니다. 마찬가지로, 참조 형식이 초기화되지 않았음을 나타내기 위해 이를 null로 설정할 수 있습니다.
이러한 차이를 처리하기 위해서는 상태 정보를 저장하기 위한 추가 변수 사용, 특수 값 사용 등 별도의 프로그래밍 작업이 필요할 수 있습니다.C#에서 nullable 형식 한정자를 사용하면 정의되지 않은 값을 나타내는 값 형식 변수를 만들 수 있습니다.

nullable 형식의 기준으로는 모든 값 형식을 사용할 수 있습니다. 예를 들면 다음과 같습니다.
int? i = 10;
double? d1 = 3.14;
bool? flag = null;
char? letter = 'a';
int?[] arr = new int?[10];


nullable 형식의 각 인스턴스에는 읽기 전용인 공용 속성이 두 개 있습니다.
  • HasValue
    HasValue bool 형식이며, 변수에 null이 아닌 값이 포함되어 있으면 true로 설정됩니다.
  • Value
    Value는 내부 형식과 동일한 형식입니다. HasValue true이면 Value에는 의미 있는 값이 포함됩니다. HasValue false인 경우에Value에 액세스하려고 하면 InvalidOperationException이 throw됩니다.

nullable 형식은 Value 속성을 사용하거나 명시적으로 캐스팅하여 일반 형식으로 캐스팅할 수 있습니다. 예를 들면 다음과 같습니다.
int? n = null;

//int m1 = n;      // Will not compile.
int m2 = (int)n;   // Compiles, but will create an exception if n is null.
int m3 = n.Value;  // Compiles, but will create an exception if n is null.

값 형식에 사용되는 미리 정의된 단항 및 이항 연산자와 모든 사용자 정의 연산자는 nullable 형식에도 사용할 수 있습니다. 피연산자가 null이면 이러한 연산자는 null 값을 생성합니다. 그렇지 않으면 연산자는 포함된 값을 사용하여 결과를 계산합니다. 예를 들면 다음과 같습니다.
int? a = 10;
int? b = null;

a++;         // Increment by 1, now a is 11.
a = a * 10;  // Multiply by 10, now a is 110.
a = a + b;   // Add b, now a is null.


nullable 형식과 비교를 수행하는 경우 nullable 형식 중 하나의 값이 null이고 다른 값이 null이 아니면 !=(같지 않음)을 제외하고 모든 비교 결과가 false입니다. 특정 비교에서 false를 반환한다고 해서 그 반대 경우가 true를 반환한다고 가정할 수는 없습니다.

?? 연산자는 null이 허용되지 않는 형식에 nullable 형식을 대입할 때 반환되는 기본값을 정의합니다.
int? c = null;

// d = c, unless c is null, in which case d = -1.
int d = c ?? -1;


이 연산자는 여러 개의 nullable 형식과 함께 사용할 수도 있습니다. 예를 들면 다음과 같습니다.
int? e = null;
int? f = null;

// g = e or f, unless e and f are both null, in which case g = -1.
int g = e ?? f ?? -1;
https://msdn.microsoft.com/ko-kr/library/ms228597.aspx

nullable 형식을 기반으로 한 개체는 이 개체가 null이 아닌 경우에만 boxing됩니다. HasValue  false인 경우 boxing하는 대신 개체 참조가 null에 할당됩니다. 예를 들면 다음과 같습니다.
bool? b = null;
object o = b;
// Now o is null.
개체가 null이 아닌 경우, 즉 HasValue true인 경우 boxing이 수행되지만 이 경우에도 nullable 개체의 기반이 되는 내부 형식만 boxing됩니다.null이 아닌 nullable 값 형식을 boxing하면 값 형식을 래핑하는 System.Nullable<T>이 아니라 값 형식 자체가 boxing됩니다. 예를 들면 다음과 같습니다.
https://msdn.microsoft.com/ko-kr/library/ms366789.aspx
C# typeof 연산자를 사용하여 Nullable 형식을 나타내는 Type 개체를 만들 수 있습니다.
System.Type type = typeof(int?);
System.Reflection 네임스페이스의 클래스와 메서드를 사용하여 Nullable 형식을 나타내는 Type 개체를 생성할 수도 있습니다. 그러나 런타임에GetType 메서드나 is 연산자를 사용하여 Nullable 변수에서 형식 정보를 가져오려고 하면 Nullable 형식이 아니라 내부 형식을 나타내는 Type 개체가 만들어집니다.
Nullable 형식의 GetType을 호출하면 형식이 Object로 암시적으로 변환될 때 boxing 연산이 수행됩니다. 따라서 GetType은 항상 Nullable 형식이 아니라 내부 형식을 나타내는 Type 개체를 반환합니다.
  int? i = 5;
  Type t = i.GetType();
  Console.WriteLine(t.FullName); //"System.Int32"
C# is 연산자도 Nullable의 내부 형식에서 작동합니다. 따라서 is를 사용하여 변수가 Nullable 형식인지 여부를 확인할 수 없습니다. 다음 예제에서는 is 연산자가 Nullable<int> 변수를 int로 처리하는 것을 보여 줍니다.
  static void Main(string[] args)
  {
    int? i = 5;
    if (i is int) // true
      //…
  }

https://msdn.microsoft.com/ko-kr/library/bb384091.aspx
bool? nullable 형식에는 true, false  null의 세 가지 값이 포함될 수 있습니다. 따라서 bool? 형식은 if, for 또는 while 등이 있는 조건문에서 사용할 수 없습니다. 예를 들어, 다음 코드는 컴파일러 오류를 발생시킵니다.
bool? b = null;
if (b) // Error CS0266.
{
}
이 코드는 null이 조건문의 컨텍스트에서 무엇을 의미하는지 명확하지 않기 때문에 컴파일되지 않습니다. 조건문에서 bool?를 사용하려면 먼저 해당 HasValue 속성을 검사하여 값이 null이 아닌지 확인한 다음 값을 bool로 캐스팅합니다. 자세한 내용은 bool을 참조하십시오. null 값을 사용하여 bool?에 대한 캐스팅을 수행하면 조건 테스트에서 InvalidOperationException이 throw됩니다. 다음 예제에서는 bool?에서 bool로 안전하게 캐스팅할 수 있는 한 가지 방법을 보여 줍니다.

bool? test = null;
// Other code that may or may not
// give a value to test.
if(!test.HasValue) //check for a value
{
    // Assume that IsInitialized
    // returns either true or false.
    test = IsInitialized();
}
if((bool)test) //now this cast is safe
{
   // Do something.
}
Checked 및 unchecked 문을 사용하면 너무 작아서 결과 값을 보유할 수 없는 변수에 결과가 저장될 때 숫자 연산에서 오버플로가 발생할 수 있는지 여부를 지정할 수 있습니다.자세한 내용은 checked  unchecked를 참조하십시오.
await 
메서드를 표시 하는 경우는 비동기 한정자를 사용할 수 있습니다에서 기다립니다 연산자 메서드를.때 충전을 제어는await 식의 비동기 메서드에 제어를 호출자에 게 반환 하 고 메서드가 진행 바뀌게 작업이 완료 될 때까지 일시 중단 됩니다.작업이 완료 되 면 실행 메서드를 다시 시작할 수 있습니다.
"비동기 방법" 섹션의 간단한 예제를 참조 하십시오 메서드(C# 프로그래밍 가이드).자세한 내용은 Async 및 Await를 사용한 비동기 프로그래밍(C# 및 Visual Basic)을 참조하십시오.
yield return
목록 또는 배열 등의 컬렉션에서 사용자 지정 반복을 수행 하는 반복기입니다.반복기를 사용 하는 수익률 반환 문은 각 요소는 한 번에 반환 합니다.경우는 yield return 코드에서 현재 위치 문의 도달 기억 됩니다.다음에 반복기가 호출 되 면 해당 위치에서 실행이 다시 시작 됩니다.
자세한 내용은 반복기(C# 및 Visual Basic)을 참조하십시오.
fixed 
fixed 문은 가비지 수집기에서 이동 가능한 변수를 재배치할 수 없도록 합니다.자세한 내용은 fixed를 참조하십시오.
lock 
lock 문을 사용하면 코드 블록에 대한 액세스를 한 번에 하나의 스레드로 제한할 수 있습니다.자세한 내용은 lock을 참조하십시오.

익명 함수
https://msdn.microsoft.com/ko-kr/library/bb882516.aspx

C#에서의 대리자 발전 과정
C# 1.0에서는 코드의 다른 부분에 정의된 메서드를 통해 명시적으로 초기화하는 방법으로 대리자의 인스턴스를 만들었습니다. C# 2.0에서는 대리자 호출 시 실행될 수 있는 무명의 인라인 문 블록을 작성하기 위한 방법으로 무명 메서드라는 개념이 도입되었습니다. C# 3.0에는 무명 메서드와 비슷한 개념이지만 표현력이 뛰어나면서 간결한 람다 식이 도입되었습니다. 이러한 두 기능을 통칭하여 익명 함수라고 합니다. 일반적으로 .NET Framework 3.5 이상을 대상으로 하는 응용 프로그램에서는 람다 식을 사용하는 것이 좋습니다.
다음 예제에서는 C# 1.0부터 C# 3.0까지 대리자 생성의 발전 과정을 보여 줍니다.
class Test
{
    delegate void TestDelegate(string s);
    static void M(string s)
    {
        Console.WriteLine(s);
    }

    static void Main(string[] args)
    {
        // Original delegate syntax required 
        // initialization with a named method.
        TestDelegate testDelA = new TestDelegate(M);

        // C# 2.0: A delegate can be initialized with
        // inline code, called an "anonymous method." This
        // method takes a string as an input parameter.
        TestDelegate testDelB = delegate(string s) { Console.WriteLine(s); };

        // C# 3.0. A delegate can be initialized with
        // a lambda expression. The lambda also takes a string
        // as an input parameter (x). The type of x is inferred by the compiler.
        TestDelegate testDelC = (x) => { Console.WriteLine(x); };

        // Invoke the delegates.
        testDelA("Hello. My name is M and I write lines.");
        testDelB("That's nothing. I'm anonymous and ");
        testDelC("I'm a famous author.");

        // Keep console window open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}
/* Output:
    Hello. My name is M and I write lines.
    That's nothing. I'm anonymous and
    I'm a famous author.
    Press any key to exit.
 */
https://msdn.microsoft.com/ko-kr/library/bb397687.aspx
람다 식을 만들려면 람다 연산자 => 왼쪽에 입력 매개 변수를 지정하고(있는 경우) 다른 쪽에 식이나 문 블록을 삽입합니다.예를 들어 람다 식 x => x * x는 이름이 x인 매개 변수를 지정하고 x 제곱 값을 반환합니다.다음 예제와 같이 대리자 형식에 이 식을 할당할 수도 있습니다.
delegate int del(int i);
static void Main(string[] args)
{
    del myDelegate = x => x * x;
    int j = myDelegate(5); //j = 25
}
식 트리 형식을 만들려면
using System.Linq.Expressions;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Expression<del> myET = x => x * x;
        }
    }
}
=> 연산자는 할당(=)과 우선 순위가 같고 오른쪽 결합성이 있습니다(연산자 문서의 "결합성" 단원 참조).

=> 연산자의 오른쪽에 식이 있는 람다 식을 식 람다라고 합니다.식 람다는 식 트리(C# 및 Visual Basic)를 만드는 데 광범위하게 사용됩니다.식 람다는 식의 결과를 반환하며 기본 형식은 다음과 같습니다.
(input parameters) => expression
괄호는 람다 식에 입력 매개 변수가 하나뿐인 경우에만 생략할 수 있고 그렇지 않으면 생략할 수 없습니다.둘 이상의 입력 매개 변수는 다음과 같이 괄호로 묶고 쉼표로 구분해야 합니다.
(x, y) => x == y
컴파일러에서 입력 형식을 유추할 수 없는 경우도 있습니다.이와 같은 경우에는 다음 예제와 같이 형식을 명시적으로 지정할 수 있습니다.
(int x, string s) => s.Length > x
입력 매개 변수가 0개이면 다음과 같이 빈 괄호를 지정합니다.
() => SomeMethod()
위의 예제에서 식 람다의 본문은 메서드 호출로 구성될 수 있습니다.하지만 SQL Server와 같은 .NET Framework 외부에서 평가되는 식 트리를 만드는 경우에는 람다 식에 메서드 호출을 사용하지 않아야 합니다.이러한 메서드는 .NET 공용 언어 런타임의 컨텍스트 안에서만 의미가 있습니다.

문 람다는 다음과 같이 중괄호 안에 문을 지정한다는 점을 제외하면 식 람다와 비슷합니다.
(input parameters) => {statement;}
문 람다의 본문에 지정할 수 있는 문의 개수에는 제한이 없지만 일반적으로 2-3개 정도만 지정합니다.
delegate void TestDelegate(string s);
…
TestDelegate myDel = n => { string s = n + " " + "World"; Console.WriteLine(s); };
myDel("Hello");
무명 메서드와 마찬가지로 문 람다는 식 트리를 만드는 데 사용할 수 없습니다.
이 문서는 수동으로 번역한 것입니다. 원본 텍스트를 보려면 포인터를 문서의 문장 위로 올리십시오. 추가 정보
번역
원본

람다 식(C# 프로그래밍 가이드)

Visual Studio 2015

람다 식은 대리자 또는 식 트리 형식을 만드는 데 사용할 수 있는 익명 함수입니다.람다 식을 사용하여 인수로 전달되거나 함수 호출 값으로 반환되는 로컬 함수를 쓸 수 있습니다.람다 식은 LINQ 쿼리 식을 작성하는 데 특히 유용합니다.
람다 식을 만들려면 람다 연산자 => 왼쪽에 입력 매개 변수를 지정하고(있는 경우) 다른 쪽에 식이나 문 블록을 삽입합니다.예를 들어 람다 식 x => x * x는 이름이 x인 매개 변수를 지정하고 x 제곱 값을 반환합니다.다음 예제와 같이 대리자 형식에 이 식을 할당할 수도 있습니다.
delegate int del(int i);
static void Main(string[] args)
{
    del myDelegate = x => x * x;
    int j = myDelegate(5); //j = 25
}
식 트리 형식을 만들려면
using System.Linq.Expressions;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Expression<del> myET = x => x * x;
        }
    }
}
=> 연산자는 할당(=)과 우선 순위가 같고 오른쪽 결합성이 있습니다(연산자 문서의 "결합성" 단원 참조).
람다 식은 메서드 기반 LINQ 쿼리에서 Where<TSource> 같은 표준 쿼리 연산자 메서드의 인수로 사용됩니다.
LINQ to Objects 및 LINQ to XML에서처럼 메서드 기반의 구문을 사용하여 Enumerable 클래스에서 Where<TSource> 메서드를 호출하는 경우 매개 변수는 System.Func<T, TResult> 대리자 형식입니다.람다 식은 이러한 대리자를 만드는 가장 간단한 방법입니다.예를 들어 LINQ to SQL에서처럼 이 메서드를 System.Linq.Queryable 클래스에서 호출하는 경우 매개 변수 형식은 System.Linq.Expressions.Expression<Func>이고, 여기서 Func는 입력 매개 변수를 16개까지 가질 수 있는 임의의 Func 대리자입니다.이 경우에도 람다 식을 사용하면 식 트리를 간단하게 만들 수 있습니다.람다 식은 Where 호출과 비슷하게 보일 수 있지만 실제로 람다 식을 통해 생성되는 개체 형식은 다릅니다.
위의 예제에서 대리자 시그니처는 형식이 암시적으로 지정된 int 형식의 입력 매개 변수 하나를 포함하고 int를 반환합니다.람다 식에도 입력 매개 변수 하나(x)와 컴파일러에서 int 형식으로 암시적으로 변환할 수 있는 반환 값이 있기 때문에 람다 식을 이 형식의 대리자로 변환할 수 있습니다. 형식 유추는 다음 단원에서 자세하게 설명합니다. 입력 매개 변수를 5로 사용하여 대리자를 호출하면 25라는 결과가 반환됩니다.
is 또는 as 연산자의 왼쪽에는 람다 식을 사용할 수 없습니다.
무명 메서드에 적용되는 모든 제한은 람다 식에도 적용됩니다.자세한 내용은 무명 메서드(C# 프로그래밍 가이드)을 참조하십시오.

=> 연산자의 오른쪽에 식이 있는 람다 식을 식 람다라고 합니다.식 람다는 식 트리(C# 및 Visual Basic)를 만드는 데 광범위하게 사용됩니다.식 람다는 식의 결과를 반환하며 기본 형식은 다음과 같습니다.
(input parameters) => expression
괄호는 람다 식에 입력 매개 변수가 하나뿐인 경우에만 생략할 수 있고 그렇지 않으면 생략할 수 없습니다.둘 이상의 입력 매개 변수는 다음과 같이 괄호로 묶고 쉼표로 구분해야 합니다.
(x, y) => x == y
컴파일러에서 입력 형식을 유추할 수 없는 경우도 있습니다.이와 같은 경우에는 다음 예제와 같이 형식을 명시적으로 지정할 수 있습니다.
(int x, string s) => s.Length > x
입력 매개 변수가 0개이면 다음과 같이 빈 괄호를 지정합니다.
() => SomeMethod()
위의 예제에서 식 람다의 본문은 메서드 호출로 구성될 수 있습니다.하지만 SQL Server와 같은 .NET Framework 외부에서 평가되는 식 트리를 만드는 경우에는 람다 식에 메서드 호출을 사용하지 않아야 합니다.이러한 메서드는 .NET 공용 언어 런타임의 컨텍스트 안에서만 의미가 있습니다.

문 람다는 다음과 같이 중괄호 안에 문을 지정한다는 점을 제외하면 식 람다와 비슷합니다.
(input parameters) => {statement;}
문 람다의 본문에 지정할 수 있는 문의 개수에는 제한이 없지만 일반적으로 2-3개 정도만 지정합니다.
delegate void TestDelegate(string s);
…
TestDelegate myDel = n => { string s = n + " " + "World"; Console.WriteLine(s); };
myDel("Hello");
무명 메서드와 마찬가지로 문 람다는 식 트리를 만드는 데 사용할 수 없습니다.

async  await 키워드를 사용하여 비동기 처리를 통합하는 람다 식과 문을 쉽게 만들 수 있습니다.예를 들어 다음 Windows Forms 예제에는 비동기 메서드 ExampleMethodAsync를 호출하고 기다리는 이벤트 처리기가 포함되어 있습니다.
비동기 람다를 사용하여 동일한 이벤트 처리기를 추가할 수 있습니다.이 처리기를 추가하려면 다음 예제에 표시된 것처럼 람다 매개 변수 목록에 async 한정자를 추가합니다.
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        button1.Click += async (sender, e) =>
        {
            // ExampleMethodAsync returns a Task.
            await ExampleMethodAsync();
            textBox1.Text += "\r\nControl returned to Click event handler.\r\n";
        };
    }

    async Task ExampleMethodAsync()
    {
        // The following line simulates a task-returning asynchronous process.
        await Task.Delay(1000);
    }
}
람다 식에는 다음과 같은 일반적인 규칙이 적용됩니다.
  • 람다 식과 대리자 형식에 포함된 매개 변수 수가 같아야 합니다.
  • 람다 식의 각 입력 매개 변수는 해당되는 대리자 매개 변수로 암시적으로 변환될 수 있어야 합니다.
  • 람다 식의 반환 값(있는 경우)은 대리자의 반환 형식으로 암시적으로 변환될 수 있어야 합니다.
람다 식의 변수 범위에는 다음과 같은 규칙이 적용됩니다.
  • 캡처된 변수는 해당 변수를 참조하는 대리자가 가비지 수집 대상이 될 때까지 가비지 수집되지 않습니다.
  • 람다 식에 사용된 변수는 외부 메서드에 표시되지 않습니다.
  • 람다 식은 바깥쪽 메서드에서 ref 또는 out 매개 변수를 직접 캡처할 수 없습니다.
  • 람다 식의 return 문에 의해서는 바깥쪽 메서드가 반환되지 않습니다.
  • 점프문의 대상이 블록 외부에 있는 경우 람다 식에 람다 함수 내에 있는 goto 문, break 문 또는 continue 문을 포함할 수 없습니다.대상이 블록 내에 있는 경우 람다 함수 블록 외부에 점프문을 사용해도 오류가 발생합니다.
https://msdn.microsoft.com/ko-kr/library/bb397675.aspx

class SimpleLambda
{
    static void Main()
    {

        // Data source.
        int[] scores = { 90, 71, 82, 93, 75, 82 };

        // The call to Count forces iteration of the source
        int highScoreCount = scores.Where(n => n > 80).Count();

        Console.WriteLine("{0} scores are greater than 80", highScoreCount);

        // Outputs: 4 scores are greater than 80            
    }
}
private static void TotalsByGradeLevel()
{
    // This query retrieves the total scores for First Year students, Second Years, and so on.
    // The outer Sum method uses a lambda in order to specify which numbers to add together.
    var categories =
    from student in students
    group student by student.Year into studentGroup
    select new { GradeLevel = studentGroup.Key, TotalScore = studentGroup.Sum(s => s.ExamScores.Sum()) };

    // Execute the query.   
    foreach (var cat in categories)
    {
        Console.WriteLine("Key = {0} Sum = {1}", cat.GradeLevel, cat.TotalScore);
    }
}
/*
     Outputs: 
     Key = SecondYear Sum = 1014
     Key = ThirdYear Sum = 964
     Key = FirstYear Sum = 1058
     Key = FourthYear Sum = 974
*/

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

람다 식은 LINQ 쿼리에만 제한되지 않습니다. 대리자 값을 사용할 수 있는 위치, 즉 무명 메서드를 사용할 수 있는 모든 위치에서 람다 식을 사용할 수 있습니다. 다음 예제에서는 Windows Forms 이벤트 처리기에서 람다 식을 사용하는 방법을 보여 줍니다. 이 예제에서 입력 값(Object MouseEventArgs)의 형식은 컴파일러에서 유추되기 때문에 람다 입력 매개 변수에 명시적으로 지정할 필요가 없습니다.

예제

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        // Use a lambda expression to define an event handler.
       this.Click += (s, e) => { MessageBox.Show(((MouseEventArgs)e).Location.ToString());};
    }
}

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

C#에서는 operator 키워드로 정적 멤버 함수를 정의하여 사용자 정의 형식에서 연산자를 오버로드할 수 있습니다.그러나 일부 연산자는 오버로드할 수 없으며 일부는 다음 표에 나열된 제한 사항이 적용됩니다.
연산자
오버로드 가능성
+, -, !, ~, ++, --, true, false
이러한 단항 연산자는 오버로드할 수 있습니다.
+, -, *, /, %, &, |, ^, <<, >>
이러한 이항 연산자는 오버로드할 수 있습니다.
==, !=, <, >, <=, >=
비교 연산자는 오버로드할 수 있지만 이 표 다음에 오는 참고 사항을 참조하세요.
&&, ||
조건부 논리 연산자는 오버로드할 수 없지만 오버로드할 수 있는 &  |를 사용하여 계산할 수 있습니다.
배열 인덱싱 연산자는 오버로드할 수 없지만 인덱서를 정의할 수 있습니다.
캐스트 연산자는 오버로드할 수 없지만 새 변환 연산자를 정의할 수 있습니다(explicit  implicit 참조).
+=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=
할당 연산자는 오버로드할 수 없지만 예를 들어 +=는 오버로드할 수 있는+를 사용하여 계산됩니다.
=, ., ?:, ??, ->, =>, f(x), as, checked, unchecked, default,delegate, is, new, sizeof, typeof
이러한 연산자는 오버로드할 수 없습니다.
https://msdn.microsoft.com/ko-kr/library/09479473.aspx

변환 연산자에는 다음과 같은 속성이 있습니다.
  • implicit으로 선언된 변환은 필요 시 자동으로 수행됩니다.
  • explicit으로 선언된 변환은 캐스팅을 사용하여 호출해야 합니다.
  • 모든 변환은 static으로 선언되어야 합니다.

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

다음은 RomanNumeral BinaryNumeral의 두 구조체를 정의하고 이 두 구조체 간의 변환을 보여 주는 예제입니다.

예제

struct RomanNumeral
{
    private int value;

    public RomanNumeral(int value)  //constructor
    {
        this.value = value;
    }

    static public implicit operator RomanNumeral(int value)
    {
        return new RomanNumeral(value);
    }

    static public implicit operator RomanNumeral(BinaryNumeral binary)
    {
        return new RomanNumeral((int)binary);
    }

    static public explicit operator int(RomanNumeral roman)
    {
        return roman.value;
    }

    static public implicit operator string(RomanNumeral roman)
    {
        return ("Conversion to string is not implemented");
    }
}

struct BinaryNumeral
{
    private int value;

    public BinaryNumeral(int value)  //constructor
    {
        this.value = value;
    }

    static public implicit operator BinaryNumeral(int value)
    {
        return new BinaryNumeral(value);
    }

    static public explicit operator int(BinaryNumeral binary)
    {
        return (binary.value);
    }

    static public implicit operator string(BinaryNumeral binary)
    {
        return ("Conversion to string is not implemented");
    }
}

class TestConversions
{
    static void Main()
    {
        RomanNumeral roman;
        BinaryNumeral binary;

        roman = 10;

        // Perform a conversion from a RomanNumeral to a BinaryNumeral:
        binary = (BinaryNumeral)(int)roman;

        // Perform a conversion from a BinaryNumeral to a RomanNumeral:
        // No cast is required:
        roman = binary;

        System.Console.WriteLine((int)binary);
        System.Console.WriteLine(binary);

        // Keep the console window open in debug mode.
        System.Console.WriteLine("Press any key to exit.");
        System.Console.ReadKey();
    }
}
/* Output:
    10
    Conversion not yet implemented
*/