C 샤프
C++과 C#의 차이점

C++ 언어와 비교할 때 C#은 다음과 같은 점에서 단순화되거나 확장되었다.
C#에는 전역 변수 및 전역 함수가 존재하지 않으며, 클래스 안에 선언되어야 한다.
C#의 bool은 오직 true와 false의 논리값만을 가질 수 있으며,상수 또는 정수형 변수에서 암시적으로 변환이 불가능하다. 직접 대입을 위해서는 변환 명령을 이용해야 한다. 반면 C++의 bool은 정수값을 대입할 수 있다. 또한 C#에서는 if나 while문 등의 비교문에서 이용하는 값도 bool 형태로 제한되는 반면, C++에서는 상수 또는 변수를 이용하여 '0이 아닌 값' 또는 '0'의 여부로 비교할 수 있다.
C#에서는 static 키워드를 오직 한 번만 초기화를 수행한다는 의미로 이용할 수 없다.
기본적으로 C#에서 포인터는 unsafe 블록 또는 unsafe 형식에서 사용하도록 정의되어 있으며, unsafe 키워드를 사용하려면 컴파일러에게 /unsafe 또는 --unsafe 스위치를 지정하도록 명시해야 한다. unsafe 블록의 사용 예는 다음과 같다.
unsafe
{
    int *pA;
}
닷넷 플랫폼에서 포인터를 다루는 기본 단위는 System.IntPtr이다.
(System.UIntPtr은 특수한 목적으로 쓰이므로 설명에서 제외한다.)
C#은 unsafe 블록 안에서 사용이 가능한 직접적인 포인터
(IntPtr.ToPointer 메서드로 void* 형식을 가져올 수 있음)도 지원한다.
메모리 관리자에 의해 관리되는 데이터는 주소값이 자주 변경되므로, 잘못된 주소를 접근하는 등의 오류를 방지하기 위해 포인터는 참조 형식의 인스턴스를 가리킬 수 없는 것이 기본 원칙이며, 참조 형식의 필드를 멤버로 가지고 있는 구조체 역시 완전한 값 형식으로 판정하지 않고 참조 형식으로 처리하기 때문에, 이 경우의 구조체의 인스턴스에 대해서도 포인터로 그 주소를 가리킬 수 없다.
C#의 포인터는 C++의 포인터와 비교하였을 때 문법적으로 다른 의미를 가진다.
C++에서 포인터는 특정한 형식의 인스턴스 또는 주소값을 가리키기 위한 목적으로 할당되는 주소값을 기억하기 위한 변수로 취급되지만
C#의 포인터는 System.IntPtr이라는 하나의 완성된 형식에 대한 확장 사양일 뿐이다.
그래서 C++의 포인터와 같은 쓰임새를 C#으로 이식할 수 없는 경우가 상당히 많다.
void* 포인터가 가리키는 값을 얻어낼 수 없고 void* 포인터에 대한 산술 연산도 수행할 수 없다.
산술 연산은 컴파일러의 옵션 지정에 따라서 /checked+ 로 지정된 경우
모든 코드 범위에서 엄격한 산술 연산 검사를 할 수 있으며 /checked- 로 지정된 경우
모든 코드 범위에서 산술 연산 검사를 하지 않도록 할 수 있다.
컴파일러 옵션과는 관계없이 unchecked 블록 안에서는 검사되지 않으며,
반대로 checked 블록 안에서는 검사가 이루어진다.
int a = 0;
unchecked
{
    a = int.MaxValue + 20;
}
checked
{
    a = int.MaxValue * 2;
}
fixed 블록을 이용하여 힙에 데이터를 고정할 수 있다.
using System;

namespace FooBar
{
    class Program
    {
        private int Test = 123;

        static void Main(string[] args)
        {
            unsafe
            {
                Program p = new Program();

                fixed (int* ptrX = &p.Test)
                {
                    Console.Out.Write(Convert.ToString(*ptrX));
                    *ptrX = 21;
                    Console.Out.WriteLine(Convert.ToString(*ptrX));
                }
            }
        }
    }
}
C#은 C++과는 달리 직접적인 메모리 해제 명령이 없으며, C++에서 포인터를 다룰 때 발생하기 쉬운 가비지나 매달린 포인터와 같은 복잡한 문제를 C#에서는 가비지 컬렉터의 능력으로 자동으로 처리한다. 하지만 가비지 컬렉터가 수집을 하기 이전에 개별적으로 처리해야 할 필요가 있는 소거 작업의 구현을 위하여 IDisposable 인터페이스를 특정 클래스에서 구현하게 된다. IDisposable 인터페이스를 구현하는 클래스는 C#의 using 구문을 이용하여 자동으로 IDisposable.Dispose 메서드를 호출할 수도 있다.
C#은 C++과는 달리 부모 클래스를 하나만 사용할 수 있다. 즉 다중 상속은 불가능하며 구현해야 하는 인터페이스는 다수개를 지정할 수 있다. 이 점은 다중 부모 클래스로부터의 상속에서만 누릴 수 있는 이점을 잃게되는 단점을 가지지만 복잡성을 최소화하고 보다 명료한 상속 관계의 의미를 만들 수 있다는 점에서는 큰 도움이 된다.
C#은 C++보다 형 안전성에 대하여 더 관대하다. 이 말은 형 안정성을 보장할 수 없다는 것도 동시에 뜻한다. System.Object 클래스가 모든 클래스의 선조 클래스이기 때문에 이러한 관대함이 가능하게 되었다. (단, unsafe 블록 내에서 사용되는 포인터 형식의 경우는 예외로 한다.)
배열과 포인터를 정의하는 문법이 다르다. 배열 문법은 자바와 유사하다. 하지만 포인터의 경우 C#은 int*, void*, byte*, ...와 같이 하나의 완성된 형식으로서 이해할 수 있지만 C++은 메모리 주소값을 저장하도록 되어있는 형태이다. 포인터를 사용하고자 하는 목적은 같지만 C++에서처럼 어떤 곳에서나 주소를 참조할 수 있는 것은 아니므로 정확한 이해가 필요하다. (다만, 특수한 GCHandle 형식을 활용하여 Pinned Object를 생성하는 경우에는 이러한 접근이 가능할 수 있으나 특성에 맞지도 않으며 심각한 성능 저하를 일으키므로 좋은 방법이라고 할 수 없을것이다.)
// C#
int[] a = new int[5];
int* pA, pB;
// C++
int a[5];
int *pA, *pB;
C#의 열거형은 그 자체가 하나의 형식이고 열거형 아래에 정의된 상수들은 멤버 상수가 된다. 하지만 C++의 열거형은 열거형 형식 그 자체의 의미보다는 상수들이 전역적으로 쓰일 수 있다는 것에 더 초점을 둔다.
형식 다형성에 대한 제약을 극복하고 형식 안정성을 향상시키기 위한 목적으로 도입한 제네릭 형식이란 것이 2.0 사양부터 존재한다. C++의 템플릿과 목표는 유사하지만 C++의 템플릿이 C++ 컴파일러보다 앞서서 처리되는 것에 비하여 C#의 제네릭 형식은 IL 메타데이터 상에 실제로 정보가 남는다. 이러한 차이점으로 인하여 마이크로소프트 비주얼 C++에는 특이한 충돌 현상이 발생하게 된다.
데이터 멤버를 다루는 구문에 의해 메서드가 호출되는 속성 기능이 있다. 이것을 정확한 이름으로는 프로퍼티라고 하며 getter 메서드와 setter 메서드로 구분된다. C#에서는 getter와 setter를 한꺼번에 사용할 수 있도록 아래와 같이 고정된 문법을 사용한다. 비주얼 베이직 닷넷의 경우에도 이와 비슷하나 프로퍼티에서도 다수의 매개 변수를 받는 것을 허용한다. 그리고 특별한 사항이 없는 대다수의 다른 언어들에서 프로퍼티는 get_foo() 메서드와 set_foo() 메서드로 구분되어 표현되곤 한다.
public string Name
{
    get
    {
        return m_name;
    }
    set
    {
        m_name = "Name :: "+value;
    }
}

public void MethodOne(string name)
{
    this.Name = "DotNet";
}
C++에서 특정 컴파일러 제작사마다 조금씩 다른 방식으로 구현되었던 런타임 형식 정보는
C#에서 리플렉션으로 확장하여 사용하는 것이 가능하다.
리플렉션은 자바 언어의 리플렉션과 같은 개념이다.
C#은 C/C++과 달리 전처리기의 사용이 제한적이다.
즉, C/C++에서 사용되던 #include나 #pragma와 같은 지시자를 C#에서는 사용할 수 없으며,
C/C++에서 매크로 상수나 매크로 함수 등을 위해 사용되던 #define이 C#에서는 매우 제한적인 용도로 사용된다.
또한 C/C++에는 없던 #region, #endregion 지시자가 새로 추가되었다.
예를 들면 다음과 같다.
#define CsDebug
#region 아래는 FooClass 선언입니다.
public class FooClass
{
    private int integer;
    #if CsDebug
    private string debugmsg;
    #endif
    public string DebugMsg
    {
        get
        {
            #if CsDebug
            return this.debugmsg;
            #else
            return null;
            #endif
        }
        set
        {
            #if CsDebug
            this.debugmsg = value.Clone() as string;
            #endif
        }
    }
}
#endregion
C#에서는 인라인 함수가 지원되지 않으며, 전역 함수나 전역 변수도 허용되지 않는다.
즉, 모든 인스턴스나 메서드는 반드시 특정 클래스의 멤버로 소속되어야 한다.
C#에서는 데이터 은닉과 보안성 향상을 위해 프렌드 함수를 지원하지 않는다.
대신 C# 3.0부터 이와 비슷한 확장 메서드를 지원하고 있다.
확장 메서드는 정적 클래스의 멤버로 있어야 하며 이 때에도 대상 클래스의 private 멤버에는 접근 할 수 없다.
public class Foo
{
    [MarshalAs(UnmanagedType.U4)]
    private uint dwValue;
    [MarshalAs(UnmanagedType.LPWstr)]
    private string lpcwValue;

    public uint DWValue
    {
        get { return this.dwValue; }
        set { this.dwValue = value; }
    }
    public string LPCWValue
    {
        get { return this.lpcwValue; }
        set { this.lpcwValue = value.Clone() as string; }
    }
}
public static class Bar
{
    public static string FooString(this Foo foo)
    {
        return string.Format("정수 값은 {0}, 문자열 값은 {1}입니다.", foo.DWValue, foo.LPCWValue);
    }
}
C# 3.0부터는 임의의 자료형인 var타입을 지원한다. var의 실제 형식은 컴파일시 결정된다.
(이 부분은 C++11에서 auto 키워드로 지원한다. )
C# 3.0부터는 기존의 SQL구문을 활용한 LINQ 식을 지원한다.
아래 예제는 정수형으로 이루어진 배열에서 100을 초과하는 값만을 추출하는 코드이다.
public List<int> linqtest(List<int> list)
{
    var result = from k in list where k > 100 select k;
    return result;
}
C++에서는 함수 포인터를 이용하여 함수의 시작점을 전달 했지만, C#에서는 보다 유연한 델리게이트와 무명 메서드를 지원한다.
public static void Print(int a, int b, Func<int> func)
{
    Console.WriteLine("{0} 더하기 {1}은 {2}입니다.", a, b, func(a, b));
}
public static void Main()
{
    Print(a, b, f => {Console.WriteLine("func가 호출되었습니다."); return a+b;});
}