C# 프로그램의 구조

C#의 핵심 조직

C#의 핵심 조직 개념은 ‘프로그램’, ‘네임스페이스’, ‘형식’, ‘멤버’, ‘어셈블리’입니다. 프로그램은 멤버를 포함하고 네임스페이스로 구성될 수 있는 형식을 선언합니다. 클래스, 구조체 및 인터페이스는 형식의 하나 입니다. 필드, 메서드, 속성 및 이벤트는 멤버의 하나 입니다.

C# 프로그램을 컴파일하면 실제로 어셈블리로 패키지됩니다. 어셈블리는 일반적으로 애플리케이션을 구현하는지 또는 *라이브러리**를 구현하는지에 따라 각각 파일 확장명 .exe 또는 .dll을 갖습니다.

어셈블리 예제

간단한 예로, 다음 코드를 포함하는 어셈블리를 생각해 볼 수 있습니다.

using System; 

namespace Acme.Collections 
{
     public class Stack<T>
     {
         Entry _top;
         
         public void Push(T data)
         {       
              _top = new Entry(_top, data);
         }

         public T Pop()
         {
             if (_top == null)
             {
                 throw new InvalidOperationException();
             }

             T result = _top.Data;
             _top = _top.Next;
             
             return result;
         }

         class Entry
         {
             public Entry Next { get; set; }
             public T Data { get; set; }
             
             public Entry(Entry next, T data)
             {
                 Next = next;
                 Data = data;
             }
         }
     }
 }

이 클래스의 정규화된 이름은 Acme.Collections.Stack입니다. 클래스에는 필드 top, 2개의 메서드 Push 및 Pop, 중첩된 클래스 Entry 등의 여러 멤버가 포함됩니다. Entry 클래스는 필드 next 및 필드 data, 생성자의 세 멤버가 포함됩니다. Stack은 제네릭 클래스입니다. 이는 사용 시 구체적인 형식으로 대체되는 T 형식 매개 변수 하나를 포함합니다.

어셈블리에는 IL(중간 언어) 명령 형식의 실행 코드와 메타데이터 형식의 기호 정보가 포함됩니다. 어셈블리가 실행되기 전에, .NET 공용 언어 런타임의 JIT(Just-In-Time) 컴파일러가 어셈블리 안의 IL 코드를 해당 프로세서에 맞는 코드로 변환합니다.

어셈블리는 코드와 메타데이터를 모두 포함하는 기능의 자체 설명 단위이므로 C#에서는 #include 지시문과 헤더 파일이 필요하지 않습니다. 특정 어셈블리에 포함된 공용 형식 및 멤버는 프로그램을 컴파일할 때 해당 어셈블리를 참조하는 것만으로 C# 프로그램에서 사용 가능해집니다. 예를 들어 이 프로그램에서는 acme.dll 어셈블리의 Acme.Collections.Stack 클래스를 사용합니다.

Acme.Collections.Stack를 사용하는 프로그램 예제

using System; 
using Acme.Collections;

class Example 
{
     public static void Main()
     {
         var s = new Stack<int>();
         s.Push(1); // stack contains 1
         s.Push(10); // stack contains 1, 10
         s.Push(100); // stack contains 1, 10, 100
         Console.WriteLine(s.Pop()); // stack contains 1, 10
         Console.WriteLine(s.Pop()); // stack contains 1
         Console.WriteLine(s.Pop()); // stack is empty
     }
 }

이 프로그램을 컴파일하려면 위의 예제에 정의된 스택 클래스를 포함하는 어셈블리를 참조해야 합니다.

C# 프로그램은 여러 원본 파일에 저장될 수 있습니다. C# 프로그램을 컴파일하면 모든 원본 파일이 함께 처리되고 서로를 제약 없이 참조할 수 있습니다. 개념적으로 처리되기 전에 모든 원본 파일이 하나의 대량 파일에 연결된 것과 같습니다. 소수의 경우를 제외하고 선언 순서는 중요하지 않으므로 C#에서는 정방향 선언이 필요한 경우가 없습니다. C#은 소스 파일을 하나의 공용 형식만 선언하도록 제한하거나 소스 파일 이름이 소스 파일에 선언된 형식과 일치하도록 요구하지 않습니다.

이점은 객체지향 프로그램이 좋은점이기도 합니다.

최신글

C# 필드 및 메서드

필드

필드 는 클래스 또는 클래스의 인스턴스와 연결된 변수입니다.

static 한정자를 사용하여 선언된 필드는 정적 필드를 정의합니다. 정적 필드는 정확히 하나의 스토리지 위치를 식별합니다. 클래스의 인스턴스가 몇 개나 만들어졌는지에 관계없이 정적 필드의 복사본은 하나뿐입니다.

static 한정자 없이 선언된 필드는 인스턴스 필드를 정의합니다. 클래스의 모든 인스턴스는 해당 클래스의 모든 인스턴스 필드의 별도 복사본을 포함합니다.

다음 예제에서 Color 클래스의 각 인스턴스는 R, G 및 B 인스턴스 필드의 별도 복사본을 갖지만 Black, White, Red, Green 및 Blue 정적 필드의 복사본은 하나뿐입니다.

public class Color 
{
     public static readonly Color Black = new Color(0, 0, 0);
     public static readonly Color White = new Color(255, 255, 255);
     public static readonly Color Red = new Color(255, 0, 0);
     public static readonly Color Green = new Color(0, 255, 0);
     public static readonly Color Blue = new Color(0, 0, 255);

     public byte R;
     public byte G;
     public byte B;

     public Color(byte r, byte g, byte b)
     {
         R = r;
         G = g;
         B = b;
     } 
}

위 예제와 같이 읽기 전용 필드 는 readonly 한정자를 사용하여 선언될 수 있습니다. 읽기 전용 필드에 대한 할당은 필드 선언의 일부로 또는 동일한 클래스의 생성자에서만 발생할 수 있습니다.

메서드

메서드 는 개체 또는 클래스에서 수행할 수 있는 계산이나 작업을 구현하는 멤버입니다. 정적 메서드 는 클래스를 통해 액세스됩니다. 인스턴스 메서드 는 클래스의 인스턴스를 통해 액세스됩니다.

메서드에는 메서드로 전달되는 값 또는 변수 참조를 나타내는 ‘매개 변수’ 목록이 있을 수 있습니다. 메서드에는 메서드에 의해 계산되고 반환되는 값의 형식을 지정하는 ‘반환 형식’이 있습니다. 메서드가 값을 반환하지 않을 경우 반환 형식은 void입니다.

형식과 마찬가지로 메서드에는 메서드가 호출될 때 형식 인수가 지정되어야 하는 형식 매개 변수 집합도 있을 수 있습니다. 형식과 달리 형식 인수는 종종 메서드 호출의 인수에서 유추될 수 있으므로 명시적으로 지정할 필요가 없습니다.

메서드의 시그니처 는 메서드가 선언되는 클래스에서 고유해야 합니다. 메서드 시그니처는 메서드의 이름, 형식 매개 변수의 수, 해당 매개 변수의 수, 한정자 및 형식으로 구성됩니다. 메서드 시그니처는 반환 형식을 포함하지 않습니다.

메서드 본문이 단일 식인 경우 메서드는 다음 예제와 같이 간결한 식 형식을 사용하여 정의할 수 있습니다.

public override string ToString() => "This is an object";

최신글

C# 구조체와 인터페이스

클래스는 상속과 다형성을 지원하는 형식을 정의합니다. 이를 통해 파생 클래스의 계층 구조를 기반으로 정교한 동작을 만들 수 있습니다. 이와 대조적으로 ‘구조체’ 형식은 보다 단순한 형식으로, 기본 용도는 데이터 값을 저장하는 것입니다.* 구조체는 기본 형식을 선언할 수 없으며, System.ValueType에서 암시적으로 파생됩니다. struct 형식에서 다른 struct 형식을 파생할 수 없으며 암시적으로 봉인됩니다.

public struct Point 
{
     public double X { get; }
     public double Y { get; }

     public Point(double x, double y) => (X, Y) = (x, y); 
}

‘인터페이스’는 클래스 및 구조체로 구현할 수 있는 계약을 정의합니다. 인터페이스는 메서드, 속성, 이벤트 및 인덱서를 포함할 수 있습니다. 인터페이스는 일반적으로 해당 인터페이스가 정의하는 멤버의 구현을 제공하지 않으며 단지 해당 인터페이스를 구현하는 클래스 또는 구조체에서 제공해야 하는 멤버를 지정합니다.

인터페이스는 ‘다중 상속’을 사용할 수 있습니다. 다음 예제에서 인터페이스 IComboBox는 ITextBox 및 IListBox를 둘 다 상속합니다.

interface IControl 
{
     void Paint(); 
} 

interface ITextBox : IControl 
{
     void SetText(string text); 
} 

interface IListBox : IControl 
{
     void SetItems(string[] items); 
} 

interface IComboBox : ITextBox, IListBox { }

클래스 및 구조체는 여러 인터페이스를 구현할 수 있습니다. 다음 예제에서 클래스 EditBox는 IControl 및 IDataBound를 둘 다 구현합니다.

interface IDataBound 
{
     void Bind(Binder b); 
} 

public class EditBox : IControl, IDataBound 
{
     public void Paint() { }
     public void Bind(Binder b) { } 
}

클래스 또는 구조체가 특정 인터페이스를 구현하는 경우 해당 클래스 또는 구조체의 인스턴스를 해당 인터페이스 형식으로 암시적으로 변환할 수 있습니다. 예를 들면 다음과 같습니다.

EditBox editBox = new EditBox();
IControl control = editBox; 
IDataBound dataBound = editBox;

최신글

C#의 클래스 및 객체

클래스

클래스 는 C#의 가장 기본적인 형식입니다. 클래스는 상태(필드)와 작업(메서드 및 기타 함수 멤버)을 하나의 단위로 결합하는 데이터 구조입니다. 클래스는 해당 클래스의 ‘인스턴스’(‘개체’라고도 함)에 대한 정의를 제공합니다. 클래스는 상속 및 다형성 과 파생된 클래스 가 기본 클래스 를 확장하고 특수화할 수 있는 메커니즘을 지원합니다.

새 클래스는 클래스 선언을 사용하여 만들어집니다. 클래스 선언은 헤더로 시작합니다. 헤더는 다음을 지정합니다.

  • 클래스의 특성 및 한정자
  • 클래스의 이름
  • 기본 클래스(기본 클래스에서 상속하는 경우)
  • 이 클래스에서 구현한 인터페이스

헤더 다음에는 구분 기호 { 및 } 간에 작성되는 멤버 선언 목록으로 구성되는 클래스 본문이 나옵니다. 다음 코드는 Point라는 간단한 클래스의 선언입니다.

public class Point 
{
  public int X { get; }
  public int Y { get; }

    public Point(int x, int y) => (X, Y) = (x, y);
}

클래스의 인스턴스는 새 인스턴스에 대한 메모리를 할당하고, 인스턴스를 초기화하는 생성자를 호출하고, 인스턴스에 대한 참조를 반환하는 new 연산자를 사용하여 만들어집니다. 다음 문은 두 개의 Point 개체를 만들고 해당 개체에 대한 참조를 두 변수에 저장합니다.

var p1 = new Point(0, 0);
var p2 = new Point(10, 20);

개체

개체가 차지하는 메모리는 개체에 더 이상 연결할 수 없을 때 자동으로 회수됩니다. C#에서는 개체를 명시적으로 할당 취소할 필요가 없으며 가능하지도 않습니다.

기본 클래스

클래스 선언은 기본 클래스를 지정할 수 있습니다. 클래스 이름 및 형식 매개 변수 뒤에 콜론과 기본 클래스의 이름을 사용하면 됩니다. 기본 클래스 지정을 생략하면 object 형식에서 파생되는 클래스와 같습니다. 다음 예제에서 Point3D의 기본 클래스는 Point입니다. 첫 번째 예제에서 Point의 기본 클래스는 object입니다.

public class Point3D : Point 
{     
  public int Z { get; set; }
  public Point3D(int x, int y, int z) : base(x, y)
  {
    Z = z;
  }
}

클래스는 기본 클래스의 멤버를 상속합니다. 상속은 클래스가 기본 클래스의 거의 모든 멤버를 암시적으로 포함함을 의미합니다. 클래스는 인스턴스 및 정적 생성자와 종결자는 상속하지 않습니다. 파생 클래스는 해당 파생된 클래스를 상속하는 멤버에 새 멤버를 추가할 수 있지만 상속된 멤버의 정의를 제거할 수 없습니다. 앞의 예제에서 Point3D는 Point에서 X 및 Y 멤버를 상속하고 모든 Point3D 인스턴스는 세 개의 속성, 즉 X, Y 및 Z를 포함합니다.

클래스 형식에서 해당 기본 클래스 형식 간에 암시적 변환이 존재합니다. 클래스 형식의 변수는 해당 클래스의 인스턴스 또는 모든 파생 클래스의 인스턴스를 참조할 수 있습니다. 예를 들어 이전 클래스 선언에서 형식 Point의 변수는 Point 또는 Point3D를 참조할 수 있습니다.

Point a = new Point(10, 20);
Point b = new Point3D(10, 20, 30);

최신글

C# Hello World 작성법

“Hello World”는 프로그래밍 언어를 배울 때 제일 처음 공부하는데 일반적으로 사용됩니다. C#에서는 다음과 같이 코딩하면 됩니다.

using System; 
class Hello
  { 
    static void Main()
      { Console.WriteLine("Hello, World");}
  }

“Hello World”는 System 네임스페이스를 참조하는 using 지시문으로 시작합니다. 네임스페이스는 계층적으로 C# 프로그램 및 라이브러리를 구성하는 방법을 제공하는 집합입니다.. 네임스페이스에는 형식 및 다른 네임스페이스가 포함됩니다. 예를 들어 System 네임스페이스에는 많은 형식(예: 프로그램에 참조되는 Console 클래스) 및 많은 다른 네임스페이스(예: IO 및 Collections)가 포함되어 있습니다.

지정된 네임스페이스를 참조하는 using 지시문을 사용하여 해당 네임스페이스의 멤버인 형식을 정규화되지 않은 방식으로 사용할 수 있습니다. using 지시문 때문에, 프로그램은 Console.WriteLine을 System.Console.WriteLine의 약식으로 사용할 수 있습니다.

“Hello World” 프로그램에서 선언된 Hello 클래스에는 단일 멤버인 Main 메서드가 있습니다. Main 메서드는 static 한정자로 선언됩니다. 인스턴스 메서드는 this 명령어를 사용하여 특정 바깥쪽 개체 인스턴스를 참조할 수 있지만 정적 메서드는 특정 개체에 대한 참조 없이 작동합니다. 관례상 Main이라는 정적 메서드가 C# 프로그램의 진입점으로 사용됩니다.

“Hello World” 출력은 System 네임스페이스에 있는 Console 클래스의 WriteLine 메서드에 의해 생성됩니다. 이 클래스는 기본적으로는 컴파일러에서 자동으로 참조되는 표준 클래스 라이브러리를 통해 제공됩니다.

닷넷이란?

C#을 구동

C# 프로그램은 CLR(공용 언어 런타임)이라는 가상 실행 시스템이며 클래스 라이브러리 세트인 닷넷에서 실행됩니다. CLR은 국제 표준인 CLI(공용 언어 인프라)를 Microsoft에서 구현한 것입니다. CLI는 언어와 라이브러리가 원활하게 함께 작동하는 실행 및 개발 환경을 만들기 위한 기초입니다.

C#으로 작성된 소스 코드는 CLI 사양을 준수하는 IL(중간 언어)로 컴파일됩니다. IL 코드와 리소스는 일반적으로 .dll 확장명과 함께 어셈블리에 저장됩니다. 어셈블리는 어셈블리의 형식, 버전 및 문화에 대한 정보를 제공하는 매니페스트를 포함합니다.

C# 프로그램이 실행되면 어셈블리가 CLR에 로드됩니다. CLR은 JIT(Just-In-Time) 컴파일을 수행하여 IL 코드를 네이티브 기계어 명령으로 변환합니다. CLR은 자동 가비지 수집, 예외 처리 및 리소스 관리와 관련된 다른 서비스도 제공합니다. CLR에서 실행되는 코드는 “관리 코드”라고도 합니다. 즉, 특정 플랫폼을 대상으로 하는 네이티브 기계어로 컴파일되는 “비관리 코드”와는 반대됩니다.

언어 상호 운용성

닷넷의 주요 기능 중 하나는 언어 상호 운용성 입니다. C# 컴파일러에서 생성된 IL 코드는 CTS(공용 형식 사양)를 따릅니다. C#에서 생성된 IL 코드는 F#의 닷넷버전, Visual Basic, C++ 또는 20개가 넘는 다른 CTS 규격 언어에서 생성된 코드와 상호 작용할 수 있습니다. 단일 어셈블리는 다른 닷넷 언어로 작성된 여러 모듈을 포함할 수 있고 형식은 마치 같은 언어로 작성된 것처럼 서로를 참조할 수 있습니다.

다양한 라이브러리

런타임 서비스 외에도 닷넷에는 광범위한 라이브러리가 포함되어 있습니다. 이러한 라이브러리는 다양한 워크로드를 지원합니다. 이들은 파일 입/출력부터 문자열 조작, XML 구문 분석, 웹 애플리케이션 프레임워크, Windows Forms 컨트롤에 이르기까지 모든 항목에 대해 다양하고 유용한 기능을 제공하는 네임스페이스로 구성됩니다. 전형적인 C# 애플리케이션은 닷넷 클래스 라이브러리를 광범위하게 사용하여 일반적인 “배관” 작업을 처리합니다.

해당글은 마이크로소프트 홈페이지에서 발췌한 내용입니다.

C# 언어 기본 정보

C# 이란

최신 개체 지향 프로그래밍 언어로 요즘 많이 쓰이는 언어입니다. 개발자는 C#을 사용하면 .NET를 활용할 수 있고 이를 활용한 강력한 앱을 사용할 수 있습니다.

C 언어 제품군에서 시작되었으며 C, C++, Java 및 JavaScript를 다룰 수 있는 사람이라면 매우 친숙한 언어입니다. 객체지향이라는 기본 맥락에서 같기 때문에 문법만 알면 금방 습득이 가능할 것입니다.

객체지향 프로그래밍

C#은 개체 지향, 구성 요소 지향 프로그래밍 언어입니다. C#은 이러한 개념을 직접적으로 지원하는 언어 구문을 제공함으로써 소프트웨어 구성 요소를 만들고 사용할 수 있는 자연 언어로 자리매김하게 되었습니다.

강력한 지속형 어플리케이션

또한 C#은 사용되지 않는 개체에서 사용하는 메모리를 자동으로 회수합니다. ‘예외 처리’는 오류 검색 및 복구에 대한 구조적이고 확장 가능한 방법을 제공합니다. ‘람다 식’은 함수형 프로그래밍 기술을 지원합니다.

int 및 double과 같은 기본 형식을 포함하는 모든 C# 형식은 단일 루트 object에서 상속됩니다. 모든 형식은 일반 작업 집합을 공유합니다. 모든 형식의 값을 일관된 방식으로 저장 및 전송하고 작업을 수행할 수 있습니다.

C#은 사용자 정의 참조 형식 및 값 형식을 모두 지원합니다. C#은 개체의 동적 할당 및 경량 구조체의 인라인 스토리지를 허용합니다. C#은 향상된 형식 안전성과 성능을 제공하는 제네릭 메서드 및 형식을 지원합니다. C#은 컬렉션 클래스의 구현자가 클라이언트 코드에 대한 사용자 지정 동작을 정의하는 데 사용할 수 있는 반복기를 제공합니다.

버전관리

C#은 시간 경과에 따라 프로그램 및 라이브러리가 호환 가능한 방식으로 개선될 수 있도록 버전 관리를 강조합니다. 버전 관리 고려 사항의 직접적인 영향을 받은 C# 설계의 측면에는 별도의 virtual 및 override 한정자, 메서드 오버로드 확인 규칙 및 명시적 인터페이스 멤버 선언에 대한 지원이 포함됩니다.

해당글은 마이크로소프트 홈페이지에서 발췌한 내용입니다.