2000년 7월에 개최된 Professional Developers Conference(PDC)에서 .NET 프로젝트와 함께 발표된 객체 지향 프로그래밍 언어(Object Oriented Programming Language)
MicroSoft에서 개발되었으며 1983에 등장한 C++의 특징과 1995년 등장한 Java에 특징을 적절하게 섞어놓은 언어이다
C#의 파일 확장자는 .cs 이다
C#은 하나의 코드만 작성하여도 다수의 플랫폼에 대응할 수 있는데 이를 가능하게 만드는 것이 .NET 이다
하나의 언어로 다수의 플랫폼을 대응할 수 있는 이유는 중간에 계층이 존재하기 때문입니다.
C++ 으로 프로그램을 제작할 경우 각각의 운영체제에 맞추어 여러 프로그램을 만들어야 한다

하지만 C#의 경우 운영체제와 C# 프로그램 사이에 계층이 존재하는데, 이를 .NET이라 한다. 이 .NET이 존재하기 때문에 하나의 코드로 여러 운영체제에서 동작할 수 있는 것이다

이러한 .NET 프로그램같은 것들을 미들웨어(Middleware)라 한다.
마이크로소프트는 어떤 플랫폼이던지 언어를 동작시킬 수 있도록 공용 언어 인프라(CLI; Common Language Infrastructure)라는 사양을 발표했는데, .NET은 이 사양에 맞춰 마이크로소프트가 구현한 프로그램인 공용 언어 런타임(CLR; Common Language Runtime)과 클래스 라이브러리 세트를 말하는 것이다

// .NET 아키텍처의 계층도
이러한 Middleware를 거치는 언어들은 한 단계를 추가적으로 거치기 때문에 필연적으로 느릴 수 밖에 없다

Tip
어셈블리란 C# 코드로 작성된 프로젝트가 빌드된 결과물을 뜻합니다.
결과물이란 실행 파일(exe)입니다.
dll은 어셈블리 파일을 뜻합니다.
어셈블리 파일이 만들어지고, 실행을 시키면 CLR이 어셈블리를 읽고, 네이티브 코드로 변환해준다. 그리고 변환 된 코드를 이용해서 프로그램을 실행시킨다.
이게 대략적인 빌드과정입니다.
C# 프로젝트를 빌드할 때 C# 코드는 CLI 사양을 준수하는 중간 언어(Intermediate Language)로 컴파일 된다.

IL코드와 프로그램에 사용되는 리소스가 함께 패키징 되어 어셈블리(Assembly)가 된다

Assembly는 서로 함께 사용되어 논리적 기능 단위를 형성하도록 빌드되는 타입 및 리소스의 컬렉션을 의미한다.
C/C++를 컴파일하면 생성되는 어셈블리 언어와는 다른 개념이기 때문에 혼동해서는 안된다
C# 프로그램을 실행하면 어셈블리가 CLR에 로드 되는데, CLR은 IL 코드를 플랫폼에 따라 JIT컴파일 혹은 AOT컴파일 과정을 수행하여 네이티브 코드(Native Code)로 변환한다
다음은 .NET Framework에서의 소스코드가 변환되는 과정이다

.NET에서는 여러 .NET 언어를 지원하기 위해 공용 타입 시스템(CTS; Common Type System)을 지원한다
.NET의 모든 형식은 값 타입(Value Type) 혹은 참조 타입(Reference Type)으로 구분되며 모든 타입은 기본 타입인 System.Object 에서 파생된다
C# 에서는 아래와 같은 계층을 가지고 있다

C#에서 값 타입은 Struct / Enumeration / 그 외 기본 제공 타입으로 구성된다
값 타입은 다음과 같은 특징을 갖는다

얕은 복사

깊은 복사



박싱(Boxing)은 값 타입을 참조 타입으로 변환하는 프로세스입니다.
언박싱(Unboxing)은 박싱된 인스턴스를 다시 값 타입으로 변환하는 프로세스입니다.
박싱과 언박싱은 많은 계산 과정을 필요로 하기 때문에 코드를 작성할 시 주의가 요구됩니다
박싱(Boxing)은 값 타입을 Object 타입 또는 값 타입에서 구현된 임의의 인터페이스 타입으로 변환하는 프로세스이다
이 프로세스는 CLR에서 Value 형식을 System.Object 인스턴스로 랩핑 하고 관리되는 힙에 저장하는데 사용된다
값 유형을 박싱하면 값이 복사되는 힙에서 값 유형과 동일한 유형의 값을 참조하는 객체 참조가 생성된다
언박싱(Unboxing)은 박싱된 인스턴스에서 값 타입을 추출하는 프로세스다
박싱이 일어날 땐 object 타입의 새로운 인스턴스를 생성해 값을 힙으로 복사하고, 언박싱이 이뤄질 땐 힙에서 스택으로 값이 복사된다


박싱과 언박싱이 일어날 때는 병목이 일어난다
박싱과 언박싱을 수행하는데에는 많은 계산 과정이 필요하기 때문에 많은 수의 박싱을 수행할 경우 성능저하의 우려가 있으므로 최대한 사용을 지양해야 한다
모두 부모 객체인 object타입 덕분입니다.
그렇기 때문에 모든 타입이 object로 변환이 가능한 것입니다.
object타입은 가장 상위타입 입니다.
정리하자면 object타입이 참조 형식(reference types)이기 때문에 object형으로 형변환이 일어 나는 것을 박싱이라고 합니다.
object에서 다시 원상태로 복귀 시키는 것을 언박싱이라고 하는 것입니다.
사용 방식은 기존에 형변환 하는 방법과 같습니다.
차이가 있다면 대상이 object가 들어 갔다는 것입니다.
박싱 예제


언박싱 오류 예제
언박싱도 확인해보겠습니다. 언박싱은 기존에 박싱한 것을 다시 푸는 작업이라고 했습니다.
- 아래와 같이 object타입을 하위차원으로 형변환을 하면 오류가 발생합니다.

언박싱 예제
다시 말해 아래와 같이 박싱한걸 다시 푸는 형태가 정상적인 방법입니다.
이때는 상위차원에서 하위차원으로 푸는 것이기 때문에 명시적으로 적어줘야 한다는 것을 잊어선 안됩니다.

가령 아래와 같은 배열을 만들고 싶다고 가정하겠습니다.
우리는 배열을 만들때 특정 타입을 지정해줘야합니다. 여기선 int로 지정했습니다.

그렇게 때문에 string 타입은 넣을 수가 없습니다.

하지만 이때 가장 상위 타입인 object를 배열 타입으로 지정해준다면 다양한 타입을 다 넣을 수 있다는 장점이 있습니다.

이때 내부적으로 데이터가 배열에 들어갈때 박싱(boxing)이 일어나게 됩니다.
그리고 출력시 다시 언박싱(unboxing)을 하게 됩니다.
정말 상당히 편리해 보입니다. 하지만 편리하다고 좋은 것이 아닙니다. 왜냐면 메모리상 비효율성이 발생되기 때문입니다.
값 형식이 참조 형식으로 바뀔때, 스택에 있는 값을 복사하여 힙에 할당시키게 되고, 언박싱시 다시 스택에 가져오는 작업을 하면서 힙에 가비지가 쌓이게 됩니다. 뿐만 아니라 단순히 힙에 넣는 작업에 비해 박싱을 통할시 20배 정도 더 많은 시간이 소요되고, 언박싱시 4배 정도의 시간이 소요됩니다.
그렇다면 object의 장점도 가져오면서 성능적 이슈를 해결할 방법은 없을까요?
있습니다. C2.0을 넘어오면서 생긴 제너릭(generic)이 이 문제들을 해결해줍니다.
.net 이란? .net 아키텍처란?
ms에서 발표한 CLI 사양에 맞춰 MS가 구현한 CLR과 Class Library세트의 오픈소스 개발자 플랫폼
C, C++ 등 미들웨어가 존재하지 않는 언어의 경우 운영체제에 맞추어 다른 코드를 작성해야 한다.
C# 의 경우 미들웨어가 존재하기 때문에 코드 하나를 작성해도 각각의 운영체제에 맞추어 자동적으로 변환되어 프로그램이 완성된다
그래서 핸드폰 안드로이드, 컴퓨터 윈도우 서로 다른 운영체제를 가지고 있지만 같은 게임을 할 수 있다.
Console.WriteLine(“Hello world”);
windows, linux, macOS에서 모두 작동이 가능한 이유는?
그 답은 CLI에 있다
예를 들어
c#에서 칠판을 작성하면 아래 언어로 CLI가 해석을 해주고, 코드를 읽게 해준다.
windows // whiteboard - 미국인 일시
linux // 黒板 - 일본인 일시
macOS // bảng đen - 베트남인 일시
windows // 미국 - whiteboard 해석한다
linux // 일본 - 黒板 해석한다
macOS // 베트남 - bảng đen 해석한다
CLI가 모든 운영체제에 맞게 번역해주니, 코드 하나를 작성해도 각각 운영체제에 사용할 수 있는 것이다.
Console.WriteLine();을 적는다면 c# 컴파일러가 IL 코드로 변환하고 이때 프로그램으로서 실행시키기 위한 다른 리소스 등 합쳐 exe 또는 dll 이라는 어셈블리 파일로 만든다.
CLR이 만들어진 어셈블리 파일을 로드하여 각각의 운영체제에 맞는 native code로 변환, 만들어진 코드(native code)를 로드하여 프로그램을 실행시킨다(프로세서가 주어진 명령을 처리한다)
반복적인 코드 작성을 없애기 위해 만들어진 class나 function 들로 만들어진 것
// C#에서 만든 공용 라이브러리
Console.WriteLine();
// 내가 만든 라이브러리
int Sum(int a, int b)
{
return a + b;
}
int num = Sum(2, 3);
// 5
★메모리 주소보기 디버그 > 창 > 메모리
&(객체) 적으면 찾을 수 있음