Tag Archives: C#

C# 6.0 완벽 가이드/ 고급 C#

대리자

  • 대리자(delegate)는 어떤 메서드를 호출하는 방법을 담은 객체
  • 대리자 형식은 그 형식의 인스턴스, 즉 대리자 인스턴스가 호출할 수 있는 종류의 메서드를 정의한다.
  • 메서드를 대리자 변수에 배정하면 대리자 인스턴스가 생성된다.
  • 대리자 인스턴스는 이름 그대로 호출자의 대리자 역할을 한다. 즉, 호출자가 대리자를 호출하면 대리자가 대상 메서드를 대신 호출해 준다. 이러한 간접 호출에 의해, 호출자와 대상 메서드 사이의 결합(coupling)이 끊어진다.
// 다음과 같은 문장은
Transformer t = Square;

// 다음 문장을 줄여 쓴 것이다.
Transformer t = new Transformer(Square);

// 한편 다음과 같은 표현식은
t(3);

// 다음을 줄여 쓴 것이다.
t.Invoke(3);

Continue reading

C# 6.0 완벽 가이드/ C#의 사용자 정의 형식

클래스

메서드

메서드에 적용할 수 있는 수정자들

정적 수정자 static
접근 수정자 public, internal, private, protected
상속 수정자 new, virtual, abstract, override, sealed
부분 메서드 수정자 partial
비관리 코드 수정자 unsafe, extern
비동기 코드 수정자 async

식 본문 메서드 (C# 6)

int Foo (int x) { return x * 2; }

int Foo (int x) => x * 2; // 위 코드와 동일

void Foo (int x) => Console.WriteLine(x); // 반환형이 void인 함수도 이런 식으로 사용할 수 있다.
  • 위의 코드와 같이 표현식이 본문인 메서드(expression-bodied method)를 줄여서 식본문 메서드라고 부른다. 중괄호와 return 키워드 대신 ‘이중 화살표’가 쓰였다.

Continue reading

C# 6.0 완벽 가이드/ C# 언어의 기초

첫 번째 C# 프로그램

컴파일

  • C# 컴파일러는 확장자가 .cs인 일단의 소스코드 파일들을 컴파일해서 하나의 어셈블리를 생성한다. 어셈블리는 .NET 프로그램 패키징 및 배포 단위이다. 어셈블리는 응용 프로그램(application)일 수도 있고 라이브러리(library)일 수도 있다.
  • 보통의 콘솔 또는 Windows 응용 프로그램은 진입점 Main 메서드를 가지고 있으며 파일 확장자는 .exe이다. 라이브러리의 확장자는 .dll이며, .exe와는 달리 진입점이 없다. 라이브러리의 주된 용도는 라이브러리 안의 코드를 다른 응용 프로그램이나 다른 라이브러리가 호출 또는 참조하는 것이다. .NET Framework는 라이브러리들의 집합이다.
  • C# 컴파일러 프로그램의 이름은 csc.exe이다. C# 프로그램은 Visual Studio 같은 IDE로 컴파일 할 수도 있고, 명령줄에서 csc를 직접 실행해서 컴파일 할 수도 있다.
csc MyFirstProgram.cs // 응용 프로그램 컴파일
csc /target:library MyFirstProgram.cs // 라이브러리 컴파일

구문

키워드와의 충돌 피하기

  • 예약된 키워드에 해당하는 식별자를 꼭 사용해야 한다면 식별자 앞에 접두사 @를 붙이면 된다.
    • @ 기호는 식별자 자체의 일부로 간주되지 않는다. 즉, @myVariable은 myVariable과 같다.
    • 접두사 @는 C#과는 다른 키워드들을 가진 다른 .NET 언어로 작성된 라이브러리를 C# 프로그램에서 사용할 때 유용할 수 있다.

Continue reading

C# 6.0 완벽 가이드/ C#과 .NET Framework 소개

(필요한 부분만 정리)

C#과 CLR의 관계

  • C#은 자동 메모리 관리와 예외 처리 같은 다양한 기능을 갖춘 런타임에 의존한다. C#의 설계는 해당 실행시점 기능들을 제공하는 Microsoft CLR의 설계와 밀접하게 대응된다.(비록 기술적으로는 C#이 CLR과 독립적이지만) 게다가 C#의 형식 체계는 CLR의 형식 체계와 밀접하게 대응된다.

CLR과 .NET Framework

  • .NET Framework는 CLR과 아주 다양한 라이브러리들의 집합으로 구성되어 있다. 그 라이브러리 집합에는 핵심 라이브러리들과 그 핵심 라이브러리들에 의존하는 응용 라이브러리들이 있다.
  • CLR은 관리되는 코드(managed code)를 실행하기 위한 런타임이다. C#은 여러 관리되는 언어(managed language) 중 하나인데, 관리되는 언어로 작성한 소스 코드를 컴파일하면 관리되는 코드가 생성된다. 관리되는 코드를 실행 파일(.exe) 또는 라이브러리(.dll) 형태로 만들고 그것을 형식 정보, 즉 메타자료(metadata)와 함께 하나의 패키지로 묶은 것을 어셈블리(assembly)라고 부른다.
  • 관리되는 코드는 중간 언어(intermediate language, IL)로 표현된다. 어셈블리를 적제(load)할 때 CLR은 어셈블리에 담긴 IL 코드를 해당 컴퓨터(x86 등) 고유의 기계어 코드로 변환한다. 이러한 변환을 담당하는 것이 CLR의 JIT(just-in-time) 컴파일러이다. 어셈블리는 원래의 원본 언어의 구성을 거의 그대로 유지하기 때문에 코드를 조사하기 쉽고 심지어 동적으로 생성하기도 쉽다.
    • ILSpy나 dotPeek, Reflector 같은 도구를 이용하면 IL 어셈블리의 내용을 조사하고 역컴파일 할 수 있다.
  • CLR은 여러 실행시점 서비스들의 호스트 역할을 한다. 그런 서시브들로는 이를테면 메모리 관리, 라이브러리 적재, 보안 서비스 등이 있다. CLR은 언어 중립적이므로 여러 언어(C#, F#, Visual Basic, .NET, Managed C++ 등)로 응용 프로그램을 개발하는 것이 가능하다.

Continue reading

C#/ Exponential Notation

지수 표기법

자리수가 큰 수를 지수를 이용해서 줄여서 표기하는 법을 말한다. 특정 숫자를 Numberx10n 꼴로 만든 후에, 지수인 n을 e 다음에 표기하는 것. 예컨대 12000000000 => 1.2e+9, 0.00000012 => 1.2e-7 같은 식으로 표현된다. 자리수가 큰 숫자를 짧게 줄여 쓰는 표기법.

e 다음에 오는 숫자가 양수면 10n 형태이기 때문에 뒤의 숫자만큼 오른쪽으로 소수점을 옮기고, 음수면 (1/10)n 형태이기 때문에 뒤의 숫자만큼 왼쪽으로 소수점을 옮긴다.

지수 표기법 변환

지수 표기법을 일반 숫자로 바꾸기

지수 표기법으로 넘어온 데이터를 일반 숫자로 바꾸려면 각 숫자 형식의 Parse를 시도하면 된다. 물론 Parse 자체보다는 TryParse가 안전하니 그 방법을 사용하는 것을 권장한다. TryParse는 out 키워드가 포함되어야 한다.

// parse를 이용한 방법
decimal x = decimal.Parse("1.2345E-02", NumberStyles.Any);

// try parse를 이용한 방법
// NumberStyle 뿐만 아니라 CultureInfo도 포함되어야 한다.
decimal result;
if( !decimal.TryParse("1.2345E-02", NumberStyles.Any, CultureInfo.InvariantCulture, out result) )
{
     // 실패시 처리
}

일반 숫자를 지수 표기법으로 바꾸기

일반 숫자를 지수 표기법으로 바꾸는 것은 매우 쉽다. 해당 숫자 형식을 ToString(“e”) 해주면 된다.

decimal num = 10000000000m;
string ex = num.ToString("e");

C#/ Linked List

Linked List의 개념

자료구조에서 배열은 초기화할 때 메모리 크기가 정해지기 때문에 메모리 관리에 뛰어나고 사용도 쉽지만 유연함이 떨어진다. 이에 반해 연결 리스트는 연결이 언제 추가, 삭제될지 모르기 때문에 메모리 상에 이곳저곳에 퍼져있게 되어 메모리 관리의 효율성은 떨어지지만 새로운 연결을 추가하거나 기존 연결을 삭제하는 유연함은 대단히 높다.

연결 리스트는 자기 자신의 데이터 + 다음 노드의 포인터로 구성되는데, 그 포인터를 이용해서 순차적인 리스트를 구성한다.

C#에서의 Linked List

C#에서는 LinkedList<T> 를 통해 연결 리스트를 사용할 수 있다. AddFirst(), AddLast(), AddAfter(), AddBefore() 등 연결 리스트의 기본적인 개념을 이용한 메서드들이 제공되고 있는데, 기본적으로 List<T> 보다 성능이 떨어지므로 List<T>를 사용하는 것을 권장한다.

연결리스트는 개념만 이해하면 좋을 듯.

C#/ Using과 IDisposable

Using과 IDisposable

C# 에서 메모리는 가비지 컬렉터가 관리해 주지만, 그 외의 열린 파일, 스트림 같은 관리되지 않는 리소스들은 인식하지 못한다. 이런 리소스들은 프로그래머가 명시적으로 해제를 해줘야 하는데 그때 사용하는게 Dispose()이다.

가비지 컬렉터가 제어할 수 없는 리소스를 제어하는 클래스가 IDisposable을 상속 받아 Dispose()를 구현하고 using을 통해 사용하면 된다.

public class Book : IDisposable
{
    public void Dispose ()
    {
        // 리소스 해제
    }
}

public class Program
{
    public void ReadBook ()
    {
        using (Book novel = new Book())
        {
            // 실행문
        }
    }
}

위와 같이 코드를 구성하면 using 블록을 빠져나갈 때 프로그램이 Dispose()를 실행시켜줘서 리소스를 자동으로 해제하게 된다. using이 네임스페이스를 지정하는 것 외에 Dispose()를 실행시키는 것으로도 쓰이는 것이다.

C#/ DLL 사용하기

C#에서 만든 DLL 사용하기

C#에서 만들어진 DLL 사용하는 방법은 매우 쉽다. using 키워드로 해당 DLL 을 불러온 후에 일반 클래스 사용하듯이 사용하면 된다.

using MyDLL;

static void Main (string[] args)
{
    // MyDLL에 정의된 클래스로 객체 정의하기
    Calcurate cal = new Calcurate();

    int resultAdd = cal.add(1, 2);
    int resultMinus = cal.minus(5, 3);
    int resultMultiply = cal.multiply(2, 4);
    int resultDivide = cal.divide(6, 3);
}

C, C++에서 만든 DLL 사용하기

C나 C++로 만든 DLL은 System.Runtime.InteropServices을 using 한 후에, DLLImport라는 애트리뷰트와 extern이라는 키워드를 이용해서 사용해야 한다.

using System.Runtime.InteropServices;

public class SqliteDatabase
{
    [DllImport("sqlite3", EntryPoint = "sqlite3_open")]
    private static extern int sqlite3_open (string filename, out IntPtr db);

    ...

    void Open (string path)
    {
        IntPtr _connection;

        if (sqlite3_open (path, out _connection) != 0) 
        {
            throw new SqliteException ("Could not open database file: " + path);
        }
    }
}

extern은 해당 메서드의 구현을 바깥 –여기서는 DLL– 에 맡긴다는 의미다. extern 한정자가 붙은 메서드는 static으로 선언되어야 한다.

extern 키워드가 들어간 함수 이름과 매개변수는 DLL 코드 안에 정의된 것과 같아야 한다. 이렇게 정의된 메서드는 일반 메서드처럼 사용할 수 있다.

C#/ String과 StringBuilder

String과 StringBuilder

string은 char[]로서 immutable 타입이다. 이것이 무슨 말인고 하니 string에 ‘+’ 연산을 하면, 현재 string에 새로운 string에 더해지는게 아니라, 현재 string과 새로운 string을 더한 새로운 string을 만들어 낸다는 이야기다.

아래와 같은 코드는 loop를 돌 때마다 추가적으로 string을 만들어 낸다. string이 char[]임을 생각해보면 사실 당연한 결과다.

string num = "";

for (int i = 0; i < 10; i++)
{
    num += i.ToString();
}

이는 자원 낭비이므로 위와 같이 string을 반복적으로 연산할 일이 있을 때는 StringBuilder를 사용하도록 권장된다. StringBuilder는 string과는 사용법이 약간 다른데, 변수보다는 메서드를 사용하는 방식에 가깝다.

StringBuilder num = new StringBuilder();

for (int i = 0; i < 10; i++)
{
    num.Append(i.ToString());
}

StringBuilder는 ToString() 으로 string 타입으로 변환시킬 수 있다.

C#/ C#의 메모리 구조

C#의 메모리는 3가지 영역으로 구분된다.

데이터

데이터를 보관하는 영역, static 등이 해당된다. static 으로 선언된 데이터는 프로그램이 시작될 때 메모리에 올라왔다가 프로그램이 종료될 때까지 메모리에서 해제되지 않는다.

스택

값형 변수들이 올라오는 영역. 메서드가 종료되면 스택 메모리는 해제된다. 메모리의 스택 영역은 컴파일시에 결정된다.

참조형 변수들이 올라오는 영역. 엄밀히 말하면 참조형 변수들은 스택과 힙을 모두 사용하는데, 힙에는 데이터가 올라오고, 스택에는 힙의 메모리 주소가 올라온다. 메모리의 힙 영역은 런타임시에 결정된다.

복수의 스택이 힙 메모리의 주소만 갖고 있으면 하나의 데이터를 여러 곳에서 사용할 수 있는 형식이기 때문에 전체 메모리 관리에 좋다.

스택과 달리 메서드가 종료되도 사라지지 않는데 –물론 주소를 들고 있는 스택 메모리는 사라짐– 만일 힙 메모리의 주소를 갖고 있는 스택이 없으면 가비지 컬렉터가 수거해 간다.