[C#] C# 9.0 .NET Framework

녹차·2024년 5월 25일

C#

목록 보기
1/2

닷넷 프레임 워크

.NET Framework

닷넷 프레임 워크는 2002년에 MS에서 발표한 응용 프로그램 개발 환경으로서 프로세스 가상 머신에 속한다.

일반적인 네이티브 언어로 만들어진 프로그램들이 운영체제에서 곧바로 실행되는 것과는 달리, 닷넷 프레임워크를 기반으로 만들어진 응용 프로그램은 반드시 닷넷 프레임워크가 미리 설치된 환경에서만 실행된다. 원도우10 버전(Windows 10 May 2019 Update)에서는 .NET Framework 4.8이 기본적으로 탑재돼 있다.

네이티브 언어(Native Language)의 예시

-> C, Assembly 언어

닷넷 프레임워크를 설치하면 가상 머신 역할을 하는 CLR(Common Language Reuntime) 구성요소가 실행될 수 있는 환경이 원도우 운영체제에 마련된다. CLR은 프로세스(EXE)가 실행되면 메모리에 함께 적재돼 실행된다. 닷넷 프로그램은 외형상 EXE/DLL로 기존 프로그램과 동일한 구조이다. 하지만 내부적으로 CLR 구성요소가 로드돼 실행되고 그 CLR이 EXE/DLL에 함께 저장돼 닷넷 코드를 실행한다.

C# 입장에서 닷넷 프레임워크를 설명하면, C# 컴파일러는 소스코드를 기계어가 아닌 IL(Intermediate Language)이라고 하는 중간 언어로 EXE/DLL 파일 내부에 생성한다. 또한 프로그램이 시작하자마자 CLR을 로드하는 코들르 자동으로 EXE 파일 내부에 추가한다. 따라서 사용자 C#으로 개발된 애플리케이션을 실행하면 내부적으로 CLR이 먼저 로드된다. 이어 CLR은 EXE 파일 내에 있는 중간 언어 코드를 로드해서 본격적인 실행 단계에 들어선다.

닷넷 호환 언어

CLR에 의해 실행되는 중간 언어는 어느 하나의 프로그래밍 언어에 종속된 것은 아니다. 어떤 언어의 컴파일러든지 결과물을 중간 언어로 생성해 낸다면 CLR이 그것을 실행할 수 있다. 이를 닷넷 호환 언어라고 하며 C# 언어는 단지 그러한 언어 중 하나에 불과하다.

닷넷 호환 언어(.Net-Compliant Language)

-> 중간 언어로 번역하는 언어

닷넷 호환 언어는 IL 코드의 결과물을 공유하기 때문에 상호 호출이 가능하다. 예를 들어 C#으로 만든 클래스 F#에서 사용할 수 있고, 심지어 다른 언어로 만든 클래스까지도 상속받을 수 있다. 현재 MS에 의해 공식적으로 제공되는 닷넷 호환 언어는 C#, Visual Basic, .Net, F#, C++/CLI가 있다. 여기에 더해 기존의 COBOL, Lisp, Python, PHP, Ruby 등의 언어도 닷넷 환경에서 실행할 수 있게 중간 언어를 산출하는 버전들이 발표됐으며 원한다면 웹에서 내려받아 사용할 수 있다.

공통 중간 언어

바이트코드(Bytecode)

-> 자바의 VM에서는 중간 언어

이와 마찬가지로 닷넷의 CLR에선느 이를 CIL(Common Interndiate Language)이라고 하며 보통은 줄여서 IL 코드, 또는 MSIL 코드라고 한다. 이는 CPU에 독립적인 결과물로서 모든 닷넷 호한 언어는 소스코드를 IL 코드로 컴파일하고, CLR이 실행될 때 IL 코드를 CPU의 기계어로 최종 번역한다.

특이하게 IL코드는 그 자체로 프로그래밍 언어 문법을 가지며 ILASM.EXE라는 컴파일러를 가지고 있다. 이러한 특징 덕분에 대체로 닷넷 호환 언어는 두 가지 방법으로 구현되고 있다. 예를 들어 COBOL언어를 닷넷용으로 만든다고 가정해 보자. 첫 번째는 C#언어처럼 COBOL 소스코드에서 곧바로 중간 언어를 생성하도록 만들 수 있다. 두 번째는 COBOL 소스코드를 일단 IL 소스코드로 변환한 다음 그것을 컴파일할 수 있는 ilasm.exe의 도움을 받아 실행 파일을 만드는 유형도 있다.

공용 타입 시스템(CTS : Common Type System)

CTS란?

-> 닷넷 호환 언어가 지켜야 할 타입(Type)의 표준 규격을 정의한 것

만약 여러분이 새로운 언어를 만들어 닷넷 프레임워크 상에서 실행하고 싶다면 CTS 규약을 만족하는 한도 내에서만 구현할 수 있다. 예를 들어, CTS에서는 클래스 상속을 하나만 받을 수 있도록 정의하고 있다. 따라서 직접 닷넷 호환 언어를 만든다면 클래스의 다중 상속을 지원하도록 만들 수 없다. 실제로 중간 언어에서는 다중 상속과 관련된 어떠한 IL 코드 표현도 제공하지 않는다. 즉, 닷넷 호환 언어는 CTS의 한계를 넘어서 구현할 수 없다.

또 한 가지 특징으로는 닷넷 호환 언어가 CTS에서 정의된 모든 규격을 구현할 필요도 없다는 점이다. 예를 들어, CTS에서는 타입의 접근성을 대해 public, private,... 등으로 나누고 있지만 여러분이 만드는 닷넷 호환 언어에서는 public만 지원하도록 만드는 것이 가능하다. 언어에서 필요하지 않다면 CTS에서 정의한 접근성을 모두 대응하지 않아도 된다.

C#과 Visual Basic .Net 언어는 CTS가 정의한 타입 시스템의 일부를 자신들의 언어 사양에 맞게 구현하고 있다. 만약 CTS 전체를 활용해 프로그램을 만들고 싶다면 IL 언어를 사용하거나 CTS 전체 규격을 표현한 언어를 새롭게 만들어야 한다.

공용 언어 사양(Common Language Specification)

CLS란?

-> 닷넷 호환 언어가 지켜야 할 최소한의 언어 사양을 정의한 것

직접 닷넷 호환 언어를 만들고 CTS 전체를 구현해야 할 필요는 없지만 적어도 CLS에 명시된 사양만큼은 완벽하게 구현해야 한다.

예를 들어, C#에서는 부호 없는(unsigned) 형식을 지원한다. 이는 CTS에 정의돼 있기 때문에 C#에서도 정의할 수 있는 것이다. 하지만 CLS에서는 unsigned 타입을 강제화하지 않았다. 따라서 C#에서 unsigned 타입이 구현됐다고 해서 다른 언어에서도 unsigned 타입이 구현됐다고 보장할 수 없다. 그런데 왜 이것이 문제되는 것일까?

닷넷 호환 언어끼리는 서로 사용할 수 있고, 상속도 받을 수 있다는 사실을 떠올려 보자. C#언어에서 unsigned 타입을 사용한느 함수를 정의했다고 가정했을 때, unsigned를 지원하지 않는 다른 언어에서는 이 함수를 사용할 때 호환성 문제가 발생한다. 따라서 서로 다른 언얼르 섞어서 프로그램을 만들어야 한다면 외부에서 사용할 기능에 대해서는 CLS를 준수해야 한다.

CLS는 두 가지 측면에서 의미가 있다. 하나는 모든 닷넷 호환 언어가 CLS에서 정의한 사양만큼은 구현해야 한다는 것이고, 다른 하는 닷넷 호환 언어끼리 호출해야 하는 경우에는 그 기능에 한해서 CLS를 만족시키도록 작성해야 한다는 것이다.

CLS, CTS와 닷넷 호한 언어의 관계를 다이어그램으로 정리하면 다음과 같다.

메타데이터

메타데이터(Metadata)란?

-> 일반적인 정의로는 데이터를 위한 데이터

예를 들어, 그림 파일에서는 그림을 나타내는 컬러 값이 사진을 이루는 "데이터"가 된다. 이런 그림 파일을 원도우의 탐색기를 통해 속성 창을 띄워 보면 또 다른 데이터가 있는 것을 확인할 수 있다. 그림은 너비와 높이, 해상도 등의 데이터를 담고 있는데, 이는 "원본 사진 데이터"를 위한 데이터에 해당하고 이를 "메타데이터"라고 한다.

프로그래밍에서 메타데이터의 정확한 의미를 이해하려면 기존 네이티브 언어의 특징을 먼저 이해해야 한다. 예를 들어 Visual C++로 다음과 같이 2개의 클래스로 정의한 경우

이 소스코드를 컴파일해서 생성한 실행 파일로부터 개발자가 만든 클래스의 어떠한 정보도 알아낼 수 없다. 왜냐하면 Visual C++ 컴파일러는 위와 같은 클래스 정보를 설명하는 메타데이터를 생성하지 않기 때문이다. 즉, 프로그래밍 언어에서는 개발자가 구현한 코드가 데이터에 해당하고, 해당 코드의 성격을 설명해주는 별도의 데이터를 메타데이터라고 한다.

CLR에서 동작하는 실행 파일은 완전하게 자기 서술적인(self-descriptive) 메타데이터를 제공하며, 외부에서는 이런 정보를 리플랙션(Reflection)이라는 기술을 통해 사용할 수 있다. 따라서 직접 닷넷 호환 언어를 만들어 컴파일러를 제공한다면 중간 언어 코드는 물론이고 그에 대한 메타데이터가 담겨 있다. 다른 사람이 만든 EXE/DLL 파일에서 어떤 클래스와 메서드가 제공되는지 확인하고 싶다면 이 메타데이터를 통해 알 수 있다.

어셈블리, 모듈, 매니페스트

C#으로 프로그램을 만드는 경우 대개 EXE/DLL 파일을 만들게 된다. 닷넷에서는 이런 실행 파일을 어셈블리(Assembly)라고 한다.

Note
기계어와 1:1 대응되는 프로그래밍 언어인 어셈블리와 같으므로 혼동할 수 있지만 닷넷 프로그래밍에서 특별한 언급이 없다면 어셈블리는 실행 파일(EXE, DLL)을 의미한다.

어셈블리는 1개의 이상의 모듈(Module)로 구성되는데, 이때 모듈 하나당 한 개의 파일이 대응된다. 그런데 여러 개의 파일이 하나의 어셈블리를 구성하고 있다면 그 목록을 관리하는 데이터가 있어야 하지 않을까? 이를 위해 모듈 중 하나는 반드시 다른 모듈의 목록을 관리한느 매니페스트(Manifest) 데이터를 담고 있어야 한다.

매니페스트를 포함하고 있지 않은 모듈은 보통 확장자가 netmodule이고, 매니페스트를 포함하는 경우에는 확장자가 DLL, EXE 이다. 어셈브릴는 그 자체가 "참조 단위"이자 "배포 단위"라는 것에 의미가 있다. 다른 사람이 만든 어셈블리에 구현된 코드를 사용하고 싶다면 매니페스트가 포함된 모듈 및 그와 관련된 모든 모듈을 함께 가지고 있어야 한다.

이론상 어셈블리가 다수의 모듈을 지원하긴 하지만 일반적으로 여러분이 개발하거나 사용하게 될 거의 모든 어셈블리가 1개의 (EXE/DLL 모듈) 파일로 구성된다. 여러 개의 모듈을 관리하는 것은 번거롭고 VS 같은 개발 도구에서도 모듈 생성을 지원하지 않기 때문에 다중 모듈을 사용하는 경우는 거의 없다.

공용 언어 기반구조

CLI(Common Language infrastructure)

-> MS에서 ECMA 표준으로 제출한 공개 규약이다. 

CLI는 CTS 명세를 포함하며, 중간 언어에 대한 코드 정의, 메타데이터와 그것을 포함하는 이진 파일(binary file)의 구조까지 표준 사양으로 기술하고 있다. 자바의 VM을 IBM과 오라클에서 구현한 것처럼, 공개된 CLI 사양은 누구나 가져가서 임의로 구현할 수 있다. 또한 IBM이 만든 JVM 위에서 컴파일된 자바 클래스 파일이 오라클의 JVM 위에서 동작하는 것처럼 CLI 사양을 준수한 구현체에서 동작하는 닷넷 파일은 또 다른 구현체에서 실행하는 것이 가능하다.

CLI 규격을 MS에서 구현한 실체가 바로 CLR이다. 게다가 MS에서는 CLI를 외부에서도 쉅게 구현할 수 있도록 최소한의 코드로 CLI를 구현한 SSCLI(Shard Source CLI)를 함께 공개했다. 그 밖에 모노(Mono) 프레임쿼르 밑 닷넷 코어(.NET Core)라는 또 다른 CLI 구현체가 오픈소스로 꾸준히 개발되고 있으며 이 프레임쿼들은 리눅스, 맥 운영체제까지 지원하고 있다.

공용 언어 런타임

CLR(Common Language Runtime)

-> CLI 사양을 따르는 가장 대표적인 VM으로서 MS가 개발해 원도우 운영체제용으로만 배포되고 있다.

CLR에는 두 가지 큰 기능이 있는데, 하나는 중간 언어를 JIT 컴파일러를 이용해 기계어로 변환하는 것이고, 다른 하나는 CG(Garbage Collector)를 제공해 동적 메모리 할당 및 회수를 지원하는 것이다.

CLR은 EXE 내에서 공개된 API의 의해 로드될 수 있다. 즉, 원도우 개발 환경에서 동작하는 기존 네이티브 응용 프로그램에서 CLR을 내장하는 것이 가능하다. 다음은 이렇게 적용된 몇 가지를 예를 보여준다.

  • CLR을 로드하는 w3wp.exe : 원도우에 포함된 웹 서버인 IIS(Internet Information Services)는 기존의 w3wp.exe 프로그램에서는 CLR을 자동으로 Load할 수 있는 기능을 추가했다. 이로써 개발자는 명시적으로 CLR을 load하는 code를 작성하지 않고도 Web App을 .Net Language로 만들 수 있다.
  • CLR을 Load하는 SQL 서버 : MS의 SQL Server는 CLR을 Load해서 내장 프로시저(Stored Procedure)를 작성할 수 있게 한다. 또한 데이터베이스의 Table에 포함되는 칼럼의 타입을 .Net의 Class로 확장할 수 있다.
  • CLR을 Load하는 명령어 셜(Shell) : 도스 시절의 배치 명령어를 기반으로 한 명령행 셸이 원도우에서도 제공되지만 기능 면에서 너무 제한적이다. MS는 .Net Framework를 출시하면서 파워셸(PowerShell)을 별도로 제공하기 시작했는데, 이 새로운 명렁어 해석하기에는 CLR이 기본적으로 로드돼 있어 닷넷용으로 만들어진 명령어를 사용할 수 있다.

CLR 자체를 관리 환경(Manged Environment)이라고도 하고, CLR이 Load되는 프로세스를 기존의 네이티브 프로세스와 구별해 관리 프로세스(Managed Process)라고 한다.

CLI와 CLR, 닷넷은 보통 구분 없이 사용된다는 점에 유의해야 한다. 예를 들어 C#과 같은 언어는 닷넷 호환 언어라는 말보다는 CLI 호환 언어라고 불러야 하는 것이 맞다. 단지 CLI 구현체 중에 CLR이 가장 대표적이고, CLR은 .Net Framework에 포함돼 있으므로 암묵적으로 혼용되는 면이 있다.

대체로 "관리"라는 단어가 들어가면 CLR 환경과 엮인다고 보면 된다. 닷넷 호환 언어 역시 C/C++ 언어와 같은 네이티브 언어와 구분하는 관리 언어(Managed Language)라고 한다.

.Net Framework

CLR의 기능만으로는 응용 프로그램을 작성하는 Developer를 만족시킬 수 없다. MS는 CLR 말고도 여러 가지 구성 요소를 함께 만들어 이를 하나의 Pakeage로 묶어 배포하는데, 이것이 바로 우리가 자주 들었던 ".Net Framework"로서, 간단히 줄여 "닷넷"이라고 표현한다.

즉 "닷넷 프레임워크 = CLR + 부가 구성 요소"라고 간단히 정의할 수 있고, 여기서 구성 요소에는 다음과 같은 것이 포함된다.

BCL(Base Class Libary)

-> MS는 특정 기능을 수행하는 타입을 미리 만들어 놓았으며 개발자는 이 기능을 이용해 좀 더 쉅게 응용 프로그램을 개발할 수 있다. 예를 들어, 문자열을 암호화해야 할 때 개발자가 직접 구현할 필요 없이 BCL에서 제공되는 암호화 관련 타입을 이용하면 된다.

부가적인 실행 파일

-> MS는 .Net Framework에 C#, VB.NET 컴파일러를 제공하고 있으며 그 밖에도 각종 유틸리티 성격의 실행 파일을 포함시켜 두었다.

GAC(Global Assembly Cache)

-> GAC는 컴퓨터에서 실행되는 닷넷 응용 프로그램이 Assembly File을 공통적으로 찾을 수 있는 전역 저장소다. 일반적으로 C:\Windows\assembly File에 위치하고 각종 DLL 파일을 담고 있다.

닷넷 응용 프로그램을 계층상으로 보면 다음과 같다.

닷넷 응용 프로그램은 기존의 모든 원도우 응용 프로그램에 대응해서 만들 수 있다. 즉, Visual C++로 만든 네이티브 프로그램이 있다면 .Net으로도 제작할 수 있다. 다음은 이에 대한 좀 더 세분화된 응용 프로그램 유형을 보여준다.

이 책의 후반부에서 위의 응용 프로그램 유형별로 C# 언어를 이용해 간단한 실습을 진행할 것이다.

거의 모든 응용 프로그램에서 여러분은 BCL을 사용하게 된다. 예를 들어, 파일을 만들어야 할 때 Win32 API를 직접 호출하는 것도 가능하지만 BCL을 사용하면 더욱 편리하게 작업할 수 있다. BCL에는 Windows 개발자가 필요로 많은 기능이 구현돼 있고 여러분은 틈틈이 BCL을 공부해둘 필요가 있다. 아래의 BCL 분류는 방대한 BCL의 일부 단면만을 보여준다.

새로운 버전의 .Net Framework가 출시될 때마다 BCL의 영역은 점점 더 커지고 있다. 그와 함께 배울 것도 많아졌지만, 달리 말하면 개발자가 작성해야 할 코드의 규모는 상대적으로 더 줄이들고 있다. 이 책에서는 지면 관계상 모든 BCL을 다룰 수는 없고 이 책을 읽어가는 데 필요한 수준의 BCL만 살펴본다.

이처럼 닷넷 응용 프로그램을 만들려면 필연적으로 .Net Framework의 전반적인 지식을 함께 공부해야 한다. 그 지식에서는 CLR/CLI/CTS/CIL이 포함되며 모든 것을 알아야 할 필요는 많지만 많이 알수록 여러분의 닷넷 프로그램 제작 능력은 더욱 향상될 것이다.

C#과 닷넷 프레임워크의 관계

C#은 .Net Framework를 기반으로 IL Code를 생성하는 컴파일러에 불과하므로 이 책에서 배우는 모든 것은 오직 '문법적인 요소'만을 제외하고는 .Net Framework의 영역에 해당하다. C#을 배운다는 것은, 곧 .Net Framework를 공부한다는 의미다. C#은 여러 도구 중 하나일 뿐 결국엔 .Net Framework가 여러분의 목표다.

그런데 왜 굳이 여러분은 C#을 선택했을까? 또는 왜 C#을 선택하는 것이 좋을까? 다른 .Net 호환 언어를 선택하는 것이 좋지 않을까?

C#이 좋은 이유는 MS가 .Net Framework를 위해 만든 언어이기 때문이다. VB.NET은 기존 비주얼베이직(Visual Basic) 개발자가 닷넷 환경으로 좀 더 쉅게 다가설 수 있도록 VB 언어의 기본 문법을 확장하는 형식으로 발전시켰기 때문에 닷넷을 위해 만들어진 것이 아니다. C++/CLI 역시 동일한 한계를 지니고 있다. C++ 언어를 바탕으로 닷넷용 응용 프로그램을 만들 수 있게 문법을 확장한 것이다. F# 언어는 어떨까? F#은 MS에서 공식적으로 지원하는 닷넷의 함수형 언어다. 즉, 함수형 언어를 통해 문제 풀이 능력을 더하기 위해 언어일 뿐 .Net Framework를 위한 언어는 아니다.

MS는 .Net을 출시하면서 그것을 가장 잘 표현할 수 있는 언어가 필요했고, 그렇게 해서 새롭게 탄생한 언어가 C#이다. C#은 .Net을 위해 태어났고 .Net과 함께 발전해 간다.

MS에서는 .Net에 새로운 기능이 추가될 때마다 그것을 이용할 수 있는 가장 첫 번째 언어로 C#을 함께 발전시킨다. 따라서 .Net Framework를 공부하기에 가장 좋은 언어가 바로 C#인 것이다.

닷넷 Core와 닷넷 표준

닷넷 코어가 공용 언어 기반구조의 또 다른 구현체이긴 하지만 다중 플랫폼에서 실행할 수 있도록 만들어졌다는 점에서 강점을 가진다. 물론 기존의 Mono Framework가 다중 플랫폼을 지원하긴 했지만 체계적이지 않은 면이 있는 데다 점점 더 다중 플랫폼에서의 실행 환경이 중요해지면서 MS가 직접 나가서 만들게 된 것이 바로 닷넷 코어다.

MS는 .Net Core의 CLI 구현과 관련해 가반 소스코드를 .Net Framework와 공유해 Mono와는 다른 안정성과 성능으로 차별화했다. 또한 소스코드를 완전히 공개했고 이를 깃허브(GitHub) Site를 통해 외부 개발자와 협업해 나가면서 더욱 빠른 개발 속도와 함께 다중 플랫폼으로의 포팅을 피하고 있다. 2020.12.18 기준으로 .Net Core 3.1을 지원하는 운영체제는 다음과 같다.

다중 플랫폼 지원이라는 장점의 이면에는 특정 플랫폼에서만 가능한 기능을 지원할 수 없다는 단점이 수반된다. 이는 자연스럽게 기반 라이브러리가 달라진다는 문제점을 야기하는데, 실제로 .Net Core와 .Net Framework는 하부 구조는 공유하고 있는 반면 기반 라이브러리 단계부터는 독자적인 구현으로 이뤄져 있다,

기반 라이브러리 각각 "Base Class Library", "Core Library"로 나눠면서 이를 바탕으로 제작되는 라이브러리의 재사용 문제가 발생한다. 예를 들어 "압축 라이브러리"를 만드는 개발자 "Core Library"에서 제공하는 클래스를 사용하면 해당 DLL은 .Net Framework용 응용 프로그램에서는 가져다 쓸 수 없는 문제가 발생한다. 이 같은 기반 라이브러리의 불일치를 해결하기 위해 다시 그들만의 표준을 만든 규격이 바로 닷넷 표준(.Net Standard) 라이브러리다.

즉, 여러분이 만들 라이브러리가 적어도 "닷넷 표준" 라이브러이 위에서 만들어졌다면 아무런 변경 없이 .Net Core와 .Net Framework 위에서 사용할 수 있게 보장해 주는 것이다.

.Net 5

지난 2019년에 MS는 데스크톱용 닷넷 버전의 출시가 4.8이 마지막이라고 발표했다. 이후 닷넷 코어 기반으로 통합하기 위한 준비를 하며 실제로 닷넷 코어 3.0에서는 데스크톱 버전에서만 지원하던 Windows Forms와 WPF 유형의 프로젝트 지원을 포함하기 시작했다. 그리고 마침내 올해 2020.11.10, 기존의 .NET Framework와 .Net Core라는 구분을 모두 없애고 "하나의 닷넷"이라는 거치 아래 ".NET 5" 버전을 발표했다.

https://dotnet.microsoft.com/ko-kr/learn/dotnet/what-is-dotnet-framework

profile
CK23 Game programmer

0개의 댓글