* 정의

 

C#은 변수나 상수에 대해 형식을 정확하게 검사하는 강력한 형식의 언어(Strong Typed Language)이다.

https://create-new-worlds.tistory.com/343

 

[C#] 강력한 형식 언어(Strongly Typed Language)

* 정의 강력한 형식 언어에서는 변수를 사용하기 전에 타입을 명시적으로 선언해야한다. int, char 등 을 포함한 모든 데이터 타입은 미리 프로그래밍 언어에 선언되어 있어야 하고 모든 변수나 상

create-new-worlds.tistory.com

 

하지만 C#에서는 지역 변수들을 명확한 타입 없이 사용할 수 있도록 var 키워드를 제공하고 있다. var 키워드는 암시적 타입(implicit type)을 가능하게 해주는 키워드로 이를 통해 변수를 선언할 수 있다. var 타입 변수는 기본 데이터 타입, 익명 타입, 사용자 정의 타입을 저장하기 위해 사용할 수 있다.

 

 

* 사용 이유

 

  • 타입을 알 수 없는 경우 선언하기 위해 사용한다. (Generic 타입, 람다, 쿼리 표현식 등) // 만약 타입을 알고 있다면 명시적으로 작성해야한다. 컴파일러가 타입을 결정하기 위해 추가 작업을 수행하기 때문에 이미 알고 있는 타입이라면 불필요한 작업이 추가되는 것이다.
  • 어떤 유형의 데이터가 변수에 저장될지 확실하지 않을 때 사용한다.
  • 익명 타입, 익명 컬렉션에 사용한다.
  • 클래스의 이름이 너무 길 때 사용한다.
  • 임포트한 네이밍 컨벤션을 따르지 않는 코드 타입에 사용한다.

 

 

* 주의 사항

 

다음과 같은 주의 사항이 있다.

 

  • 선언과 동시에 초기화된 지역 변수에만 사용 가능하다.
  • 클래스의 필드로 사용될 수 없다.
  • var 변수는 초기화 표현식에서 사용될 수없다.
  • 여러 var 변수를 동일한 statement에서 초기화할 수 없다.
  • var 로 받는 타입이 스코프안에 있는 경우 var 키워드는 해당 타입이름으로 확인된다.

 

'C#' 카테고리의 다른 글

[C#] ref, out  (0) 2022.06.28
[C#] 강력한 형식 언어(Strongly Typed Language)  (0) 2022.06.28
[C#] 박싱과 언박싱(Boxing and Unboxing)  (0) 2022.06.28
[C#] object  (0) 2022.06.28
[C#] string vs StringBuilder  (0) 2022.06.28

* 정의

 

- 박싱(Boxing)

 

박싱이란 값 타입을 object나 인터페이스 타입(해당 값 타입이 상속하고 있는 인터페이스)으로 변환하는 과정이다. CLR이 값 타입을 박싱할 때 값을 object(System.Object)에 래핑하여 힙에 저장된다.(원래 기본적으로 값 타입은 스택에 저장된다.)

 

 

- 언박싱(Unboxing)

 

언박싱이란 object로 부터 값 타입을 추출하는 과정이다.

 

 

박싱은 암묵적으로 이루어지고 언박싱은 명시적으로 수행된다.  C#에서 박싱과 언박싱을 통해 어떤 값 타입이라도 object로 다룰 수 있게 된다.

 

 

* 동작 방식

 

- 박싱과 언박싱이 발생하는 시점

 

예를 들어 값 타입 int i 와 object o 사이의 박싱 언박싱 과정은 다음과 같은 코드에서 나타난다.

 

i 가 박싱되고 o에 할당되는 과정이다.

int  i = 3;

// 박싱
object o = i;

 

o가 언박싱되고 i에 할당되는 과정이다.

object o = 3;

// 언박싱
i = (int)o;

 

 

박싱과 언박싱은 둘 다 비싼 연산이다. 박싱 연산은 힙에 할당하는 작업도 포함되어 있기 때문에 더 비싸다. 내부 동작 원리를 확인해보면 이유를 알 수 있다.

 

 

- 박싱의 원리

 

박싱은 값 타입을 가비지 컬렉터가 관리하는 힙에 할당하기 위해 사용되며, 값 타입에서 object, 인터페이스 타입(값 타입이 상속 받고 있는 인터페이스)으로의 암묵적 변환을 의미한다. 값 타입을 박싱하는 것은 object 인스턴스를 힙에 할당하고 값을 새로운 object에 복사하는 작업이다. 새롭게 힙에 할당하기 때문에 박싱된 값 타입(힙)과 값 타입 원본(스택)은 독립된 메모리 공간에 위치한다.

 

 

 

ildasm을 통해서 보면 OpCode가 box인 것을 확인할 수 있다.

 

 

- 언박싱의 원리

 

언박싱은 object나 인터페이스 타입에서 값 타입으로의 명시적 변환을 의미한다. 언박싱 연산은 다음과 같이 구성된다.

 

  • object 인스턴스를 검사하여 변환할 값 타입으로 object에 박싱되었는지 확인한다.
  • 인스턴스에서 값 타입 변수로 값을 복사한다.

 

 

 

ildasm을 통해서 보면 OpCode가 unbox인 것을 확인할 수 있다.

 

 

런타임에서 문제 없이 값 타입 언박싱이 수행되려면 언박싱할 값 타입이 이전에 해당 값 타입을 박싱하여 생성된 객체(에 대한 참조)가 언박싱 되어야 한다.

 

null을 언박싱하면 NullReferenceException, 호환불가능한 값으로 언박싱하면 InvalidCastException이 발생한다.

int i = 3;
object o = i; // 박싱
//short s = (short)o; // 언박싱과정에서 InvalidCastException 발생

object? o2 = null;
int i2 = (int)o2; // 언박싱과정에서 NullReferenceExceptino 발생
// 사실 (int) 으로 캐스팅을 시도하는 시점에서 컴파일러가 경고 메시지를 출력한다.

 

 

* 박싱 언박싱 유무 성능 비교

 

object 타입을 요소로 가지고 있는 Collection의 ArrayList와 여러 타입 인수를 통해 요소의 타입을 결정할 수 있는 Generic Collection의 List를 간단히 성능 비교해보았다.

ildasm을 통해서 보았을 때 box, unbox 명령어가 Collection 버전에서만 나타났다.

 

 

 

 

'C#' 카테고리의 다른 글

[C#] 강력한 형식 언어(Strongly Typed Language)  (0) 2022.06.28
[C#] var  (0) 2022.06.28
[C#] object  (0) 2022.06.28
[C#] string vs StringBuilder  (0) 2022.06.28
[C#] Nullable 타입  (0) 2022.06.28

* 정의

 

C#의 모든 타입은 object의 상속을 받고 있다. 기본 데이터 타입, 복합 데이터 타입 그리고 그 타입이 참조 타입이든 값 타입이든 예외 없이 모두 object이다. ildasm 툴로 확인하면 모두 object(System.Object)를 상속받고 있다는 것을 볼 수 있다. 간단히 계층 구조에서 루트이다. 심지어 값 타입을 나타내는 System.ValueType 조차 object를 상속받고 있다.

 

object는 C#의 모든 타입을 다룰 수 있으며 기본적인 기능과 리플렉션관련 기능을 제공한다.

 

< 간단한 계층 구조 다이어그램 >

 

< ildasm으로 봤을 때 System.Object를 상속받는다. >

 

< 값 타입을 나타내는 System.ValueType에서 object의 가상함수를 오버라이딩하고 있다. >

 

 

* 동작 방식

 

- object의 가상 함수

 

암시적으로 object를 상속 받고 있기 때문에 사용자에게 특정 기능을 구현 코드를 강요하지는 않지만 다음과 같은 가상 함수를 오버라이딩하여 사용할 수 있다.

 

다음과 같은 종류를 가지고 있다.

 

  • Equals : 객체간 비교를 지원하기 위해 오버라이딩한다.
  • GetHashCode : 객체를 구분하기 위한 객체에 해당하는 값(숫자)를 생성하기 위해 오버라이딩한다. 이를 기반으로 해시 테이블의 사용을 지원한다.
  • ToString : 클래스 인스턴스를 설명하는 문자열을 만들기 위해 오버라이딩한다.
  • Finalize : 객체를 가비지 컬렉터가 수거하기 전에 리소스나 정리 관련 코드를 실행하기 위해 오버라이딩한다.

 

위에서 3가지 함수의 시그니처는 다음과 같다. 필요에 따라 구현하면 된다.

  • public virtual bool Equals(Object? obj);
  • public virtual bool Equals(Object? obj);
  • public virtual string? ToString();

 

Finalize는 소멸자를 통해 선언할 수 있다. 자식 클래스 소멸자 > 부모 클래스의 소멸자 호출이 보장되도록 코드가 생성되기 때문에 C++처럼 가상 소멸자를 신경쓸 필요 없다.

 

 

- object 사용 시 주의 사항 : Boxing Unboxing

 

예를 들어 C#의 Collection과 같은 여러 타입에 대해 처리할 수 있는 컨테이너 형 클래스를 설계한다고 가정해보자.

 

모든 타입은 object 타입이므로 object를 내부 객체로 가지도록 만들 수 있다. 하지만 이렇게 설계하게 되면 박싱과 언박싱 과정이 발생하게 된다.

 

박싱 과정을 방지하기 위해 다음과 같은 방법을 고려해볼 수 있다.

  • object타입을 받는 일반적인 메소드를 만들고 특정 타입에 대한 오버로딩된 메소드를 만든다. 이렇게 오버로딩된 메소드들에서는 박싱 과정이 발생하지 않는다. 하지만 지원하지 않는 타입이 들어왔을 때 박싱 과정을 거치게 된다.
  • 제네릭(generic)을 사용하도록 디자인한다. CLR은 클래스 객체를 만들고 제니릭 타입 인수를 지정할 때 닫힌 제네릭 형식(closed generic type, 타입을 확정한다는 뜻인 것 같다.)을 만든다. 여기서 메소드는 타입 별로 존재하고 매개변수를 박싱하지 않고 호출될 수 있다.

 

 

 

'C#' 카테고리의 다른 글

[C#] var  (0) 2022.06.28
[C#] 박싱과 언박싱(Boxing and Unboxing)  (0) 2022.06.28
[C#] string vs StringBuilder  (0) 2022.06.28
[C#] Nullable 타입  (0) 2022.06.28
[C#] 값 타입과 참조 타입(Value type, Reference type)  (0) 2022.06.28

* string vs StringBuilder

 

- 기본 비교

 

string 클래스는 값 타입처럼 동작하는 불변 참조 타입이다. 한번 생성되면 수정할 수 없다. 따라서 string에서의 수정은 새로운 string 객체를 할당해서 새로운 string 객체를 참조하는 방법을 사용한다.

 

StringBuilder는 가변 참조 타입이다. StringBuilder에서는 필요한 경우 더 많은 문자를 저장하도록 확장할 수 있다. string 클래스와 다르게 StringBuilder에서의 수정은 새로운 StringBuilder 객체를 생성하지 않고 기존 객체를 확장한다.

 

 

- 사용처

 

일정하게 문자열이 유지되는 경우에는 string 객체를 사용하고 문자열 수정이 많을 것이라고 예측되는 경우 StringBuilder를 사용한다. string과 StringBuilder의 문자열 수정 관련해서 성능 분석한 자료를 보면 성능 차이가 크게 나는 것을 볼 수 있다.

 

https://www.infoworld.com/article/3616600/when-to-use-string-vs-stringbuilder-in-net-core.html

 

When to use String vs. StringBuilder in .NET Core

Take advantage of these best practices when working with strings in .NET Core for the optimal performance of your applications.

www.infoworld.com

 

https://www.c-sharpcorner.com/UploadFile/41e70f/performance-analysis-for-string-and-stringbuilder/

 

Performance Analysis For String and StringBuilder

This article will give you an overview of when and how to use the String and StringBuilder classes with proper statistical data using the CLR Profiler.

www.c-sharpcorner.com

 

 

- string(불변 문자열)이 필요한 이유(Java 기준으로 설명)

 

근데 어차피 변경되지 않을거면 그냥 StringBuilder를 사용해도 되지 않을까? 그냥 전부 다 StringBuilder로 쓰지 왜 굳이 불변 참조 타입인 string 클래스를 따로 만들었을까?

 

1. 문자열 풀(String Pool)

 

불변 문자열 string은 변경되지 않기 때문에 문자열 리터럴을 캐싱하고 재사용하면 많은 힙 공간이 절약된다.

"hello"라는 문자열이 있다고 가정했을 때 해당 문자열을 가지는 string 객체들은 String Pool에서 동일한 객체를 참조한다.

 

Java의 String Pool은 JVM에 의해 문자열들이 저장되는 특별한 메모리 공간이다. 이 문자열들은 변경할 수 없기 때문에 JVM은 각 리터럴 문자열의 복사본을 하나만 저장하여 메모리를 최적화한다. 이를 Interning이라고 한다.

 

s1과 s2는 String Pool에서 동일한 객체를 참조하는 것을 볼 수 있다.

 

C#에서 BenchmarkDotNet을 통해 같은 문자열을 다룰 때와 다른 문자열을 다룰 때 성능 분석을 간단히 해보았다. 정확한 환경에서 테스트한 것은 아니지만 메모리 차이를 확인할 수 있었다.

 

 

2. 보안

 

string을 통해서 로그인 정보, 네트워크 연결과 같은 민감한 정보를 다룰 때 좋다.

 

다음과 같은 함수를 생각해보면

void criticalMethod(string userName) 
{
    // 보안 검사
	
    // string이 변경될 수 있다면 보안 검사 이후에도 언제든지 변경할 수 있기 때문에 보안에 취약하다. 
    // 다른 스레드에서 userName에 대한 참조를 가지고 있으면 다른 스레드에서도 변경될 수 있다.
    
    // 중요 처리 
}

 

 

만약 string이 변경될 수 있다면 보안 검사 이후에도 언제든지 변경할 수 있기 때문에 보안에 취약하다.

또한 다른 스레드에서 userName에 대한 참조를 가지고 있으면 다른 스레드에서도 변경될 수 있다.

 

하지만 string이 불변성 덕분에 안전성을 보장할 수 있다.

 

 

3.  동기화

 

string이 불변이기 때문에 여러 스레드에서 액세스할 때 변경되지 않음을 보장할 수 있다. 변경될 때 문자열을 변경하는 것이 아니라 문자열 풀에 생성되기 때문에 안전하다.(thread safe)

 

 

4.  해시코드 캐싱

 

불병성은 문자열이 변하지 않는다고 가정해주기 때문에 해시 코드를 계산하는 함수에서 첫 번째 호출에서만 해시가 계산되고 그 이후에는 캐시된 동일한 해시코드를 반환한다.

 

 

< 결론 >

 

문자열 풀을 활용하여 재사용으로 힙 메모리를 절약하고, 해시에 대한 성능을 높였으며, 불변성으로 외부에서 변경되지 않음을 보장해준다.

 

 

[참고한 링크] Java에도 불변 문자열 클래스가 존재하는데 그 이유에 대해 다룬 링크이다. 자세하게 설명하고 있다.

https://www.baeldung.com/java-string-immutable

 

Why String is Immutable in Java? | Baeldung

Explore why Strings in the Java language are immutable.

www.baeldung.com

 

'C#' 카테고리의 다른 글

[C#] 박싱과 언박싱(Boxing and Unboxing)  (0) 2022.06.28
[C#] object  (0) 2022.06.28
[C#] Nullable 타입  (0) 2022.06.28
[C#] 값 타입과 참조 타입(Value type, Reference type)  (0) 2022.06.28
[C#] .NET  (0) 2022.06.28

* 정의

 

null을 가질 수 있도록 하기 위해 정의된 타입이다.

 

처음에는 값 타입에서 비워진 상태(null)를 가질 수 있도록 하기 위해서 사용되었다.

C# 8.0부터는 참조 타입에서도 null을 가질 수 있는 지 명시하도록 하고있다. 명시하지 않으면 경고 메시지가 출력된다.

 

 

* 동작 방식

 

null 값을 가질 수 있도록 하기 위해서 데이터 타입 뒤에 '?'를 붙여주면 된다.

int? value1 = null;
float? value2 = null;

 

 

- Nullable 클래스와 값 타입

 

값 타입에 ? 를 붙였을 때 어떤 일이 발생하는 지 조금 자세히 보기 위해 ildasm 툴로 확인해보면 다음과 같은 결과가 나온다.

값 타입에 System.Nullable<> 을 씌워서 사용하게 된다. System.Nullable 역시 struct이기 때문에 값 타입이다.

 

Nullable<> 클래스의 Value라는 프로퍼티를 통해서 실제 값에 접근할 수 있다. 그리고 사용 전에는 항상 HasValue라는 프로퍼티나 'null == myVar'(HasValue와 동일하다.) 이런 식으로 null 체크를 하고 사용해야한다. 만약 null 체크를 하지 않고 사용하려고하면 컴파일러가 경고 메시지를 던진다. 그럼에도 사용한다면 런타임에서 크래시가 발생한다.

 

다음과 같이 변경해서 사용한다.

 

 

- Nullable 참조 타입(Nullable Reference Type, NRT)

 

원래는 참조 타입에 대해 기본 값을 nullable로 정의하고 있었지만(추가 코드 없이 그냥 null로 할당 가능했지만) C#8.0 부터는 기본 값을 Non-nullable로 정의하고 있다.(명시적으로 지정하지 않으면 변수가 null이 아니라고 가정한다.)

// MS에서 NullReferenceException를 고치기 위해 그렇게 만들었다.

 

만약 명시적으로 작성하지 않고 null을 할당하면 경고 메시지가 나온다.

 

다음과 같이 사용해야한다.

 

 

NRT에서는 두 개의 연산자를 제공한다.

  • ? : 값 타입과 동일한 구문이다. 해당 객체가 널이될 수 있다고 컴파일러에게 알려준다.
  • ! : null forgiving operator으로 컴파일러에게 해당 값이 null이 아니라는 것을 알려준다. 프로그래머가 null 값이 아님을 확실하게 알고 있지만 컴파일러가 분석을 잘 못해서 null 값이라고 판단하는 경우 사용한다. 이를 사용하면 컴파일러는 더이상 해당 변수를 체크하지 않는다. 판단을 잘못하게 되면 런타임에 null이 발생할 수도 있기 때문에 신중하게 사용해야한다.

 

다음 글에서 조금 더 자세한 정보를 확인할 수 있다.

https://blog.miguelbernard.com/c-8-0-nullable-reference-types-are-here

 

C# 8.0 Nullable Reference types are here!

C# 8.0 just rolled out with a lot of new features. One of the most important ones is the support of nullable reference types (NRT)

blog.miguelbernard.com

 

'C#' 카테고리의 다른 글

[C#] object  (0) 2022.06.28
[C#] string vs StringBuilder  (0) 2022.06.28
[C#] 값 타입과 참조 타입(Value type, Reference type)  (0) 2022.06.28
[C#] .NET  (0) 2022.06.28
[C#] abstract, sealed  (0) 2022.04.08

* 정의

 

C#에서는 값을 메모리에 저장하는 방법에 따라 데이터 타입을 크게 2가지로 분류한다.

 

  • 1. 값 타입(Value type)
  • 2. 참조 타입(Reference type)

 

* 값 타입(Value type)

 

- 정의

 

값 타입은 데이터의 값을 직접 메모리 공간에 보유하고 있는 경우를 의미한다.

값 타입 변수는 스택에 할당된 메모리에 데이터의 값을 직접 포함하는 변수를 의미한다.

 

 

- 특징

 

@ 스택에 데이터의 값을 저장하는 것은 효율적이지만, 값 타입의 제한된 생명주기는 다른 클래스와 데이터를 공유하기에 비효율적이다.

 

@ 각 값 타입 변수는 데이터의 고유한 복사본을 가지고 있기 때문에 (ref, out 키워드를 사용하지 않는다면)메소드를 통해서 이 변수를 변경할 수 없다. 값 타입 변수를 메소드를 통해 넘겨주게 되면 시스템은 이 변수를 복사하여 새롭게 변수를 만들게 된다. 

 

@ 스코프를 빠져나가면 값이 스택에서 삭제된다.

 

@ C#의 값 타입은 다음 타입으로 분리된다.

  • 단순 타입
  • 열거형 타입
  • 구조체 타입
  • nullable 값 타입

 

@ 값 타입은 System.ValueType을 상속받는다.

 

@ 인터페이스를 제외하고 상속받을 수 없다. // IL에서 확인해보면 Sealed Class로 정의된다.

 

 

ildasm 툴로 확인한 값 타입

 

 

* 참조 타입(Reference type)

 

- 정의

 

값 타입가 다르게 데이터의 값을 직접 메모리에 저장하지 않는다. 대신 데이터의 값이 저장된 메모리를 저장한다. 간단히 참조 타입은 데이터의 값이 들어있는 다른 메모리 공간에 대한 포인터라고 생각하면 된다.

 

 

- 특징

 

@ 참조 타입은 데이터 값을 힙에 저장되고 해당 데이터 값이 존재하는 힙 메모리 주소를 스택에 저장한다.

 

@ 참조 타입을 선언하는 것은 오버헤드가 더 크지만 다른 클래스에서 접근할 수 있다는 장점이 있다.

 

@ 참조 타입을 사용하면 서로 다른 변수가 같은 객체를 참조하도록 할 수 있다. 참조 타입 변수를 메소드를 통해 넘겨주게 되면 이 데이터 값에 대한 새로운 복사본을 만들지 않는다. 대신 주소만 넘겨주게 된다. 만약 메소드에서 변수가 변경되면 원본 참조 타입에 영향을 준다.

 

@ 참조 타입 변수의 스코프를 벗어나게 되면 메모리는 바로 힙에 반환되지 않고 가비지 컬렉터가 해당 데이터가 더 이상 쓰이지 않을 때 수거하게 된다.

 

@ C#의 참조 타입은 다음 타입으로 분리된다.

  • 클래스 타입
  • 인터페이스 타입
  • 배열 타입(요소가 값 타입인 경우 포함)
  • 델리게이트 타입
  • nullable 참조 타입 // C# 8.0부터 명시적으로 nullable을 표현하도록 하고 있다.

@ 참조 타입은 System.Object를 상속받는다.

 

@ 90%이상은 ref, out 키워드를 사용하나 안하나 똑같이 동작한다. (string과 같은 불변 참조 타입 제외)

 

 

ildasm 툴로 확인한 참조 타입

 

 

* 값 타입(Value type) vs 참조 타입(Reference type)

 

  값 타입(Value type) 참조 타입(Reference type)
Base 클래스 System.Object System.ValueType
정의 방법 struct로 정의 class로 정의
메소드에 참조로 넘겨주는 방법 ref, out 키워드 사용 일반적으로 참조로 넘김
불변 참조 타입의 경우 ref, out 키워드를 사용
데이터 값의 저장 위치 스택
할당 시 오버헤드 작다 크다
생명 주기 스코프를 빠져나가면 바로 삭제 스코프를 빠져나가면 가비지 컬렉터의 판단 하에 적절한 시점에 삭제
타입 종류
  • 단순 타입
  • 열거형 타입
  • 구조체 타입
  • nullable 값 타입
  • 클래스 타입
  • 인터페이스 타입
  • 배열 타입(요소가 값 타입인 경우 포함)
  • 델리게이트 타입
  • nullable 참조 타입 // C# 8.0부터 명시적으로 nullable을 표현하도록 하고 있다.
상속 가능 여부 sealed class로 정의되기 때문에 인터페이스만 상속 가능하다. 사용자가 sealed 로 정의하지 않았으면 어느 클래스든 상속 가능하다.

 

'C#' 카테고리의 다른 글

[C#] string vs StringBuilder  (0) 2022.06.28
[C#] Nullable 타입  (0) 2022.06.28
[C#] .NET  (0) 2022.06.28
[C#] abstract, sealed  (0) 2022.04.08
[C#] 정적 클래스(static class)  (0) 2022.04.08

* 정의

 

.NET은  다양한 애플리케이션을 개발하기 위한 개발자 플랫폼으로 여러 도구와 프로그래밍 언어, 라이브러리로 구성되어 있다. .NET코드를 여러 플랫폼(Windows, macOS, Linux, IOS, Android)에서 실행시키기 위해 다양하게 .NET을 구현하고 있다. 이러한 크로스 플랫폼 구현은 여러 환경에서 웹 사이트, 서비스, 콘솔 앱을 실행시킬 수 있도록 해준다.

 

 

- .NET Framework

 

.NET Framework는 .NET의 오리지널 구현 버전으로 Windows 환경에서 웹 사이트, 서비스, 앱 등의 실행을 지원한다. 간단히 실행 중인 앱에 다양한 서비스를 제공하는 Windows용 관리 실행 환경이다.

 

 

* .NET Framework의 구성

 

.NET Framework의 메인 구성 요소는 CLR(Common Language Runtime)과 .NET Framework Class Library이다.

 

- CLR(Common Language Runtime)

 

CLR은 실행중인 앱들을 관리하는 실행 엔진이다. CLR은 가비지 컬렉션, 타입 안전성, 예외 처리, 스레드 관리와 같은 서비스를 제공한다.

 

 

- Class Library

 

Class Library는 API들과 일반적인 기능을 위한 타입들을 제공한다. 예를 들어보면 문자열, 날짜, 숫자를 위한 자료형을 제공하고 파일을 읽고 쓰는 API, 데이터 베이스에 연결하는 API 등을 제공한다.

 

 

- .NET Framework가 제공 중인 서비스

 

  • 메모리 관리 : 일반적인 프로그래밍 언어에서는 객체의 생명주기를 관리하기 위한 메모리 할당 해제를 수행해야한다. .NET Framework에서는 CLR에서 알아서 해준다.
  • 공용 형식 시스템(Common Type System) : 전통적인 프로그래밍 언어에서는 기본 타입들은 컴파일러가 정의하기 때문에 언어 간 상호 운용성을 복잡하게 만든다. .NET Framework에서는 기본 타입은 .Net Framework 타입 시스템에 의해 정의되고 .NET Framework를 사용하는 모든 언어에서 공통이다.
  • 언어 상호 운용성(interoperability) : .NET Framework에서 각 언어의 컴파일러는 모두 CIL(Common Intermediate Language)로 컴파일 한다. CIL은 모든 언어가 만나는 중간 지점이라고 보면 된다. 이 CIL은 다시 런타임에 CLR가 플랫폼에 따라 적절하게 컴파일한다. 이러한 과정을 거치기 때문에 다른 언어로 작성된 루틴에 접근할 수 있다.

 

추가 정보는 다음 링크에서 확인할 수 있다.

https://docs.microsoft.com/en-us/dotnet/framework/get-started/?WT.mc_id=dotnet-35129-website#Introducing 

 

Get started with .NET Framework - .NET Framework

Get started with .NET Framework, which is a runtime execution environment that manages apps. It contains a common language runtime (CLR) and an extensive class library.

docs.microsoft.com

 

 

- 실행 과정

 

.NET 앱들은 C#, F#, Visual Basic 프로그래밍 언어로 작성되며, 코드는 특정 언어에 영향을 받지 않는 CIL(Common Intermediate Language)로 컴파일 된다. 컴파일된 코드(CIL)는 어셈블리로 dll또는 exe파일에 저장된다.

 

앱이 실행되면 CLR은 어셈블리를 가져와서 JIT(Jist-In-Time)  컴파일러를 사용하여 기계어로 변환한다. 변환된 기계어는 컴퓨터의 특정 아키텍처에서 실행될 수 있는 형식이다. 

 

2번의 컴파일 과정을 거치는 이유 : CLR은 C#, Visual Basic 등 여러 언어를 지원하도록 설계되어 있다. 이를 실현시키기 위해 언어들이 만나는 지점을 CIL이다. 이 언어로 쓰인 코드는 다시 CLR이 자신이 설치된 플랫폼에 최적화시켜 컴파일 후 실행하게 된다.

 

 

 

'C#' 카테고리의 다른 글

[C#] string vs StringBuilder  (0) 2022.06.28
[C#] Nullable 타입  (0) 2022.06.28
[C#] 값 타입과 참조 타입(Value type, Reference type)  (0) 2022.06.28
[C#] abstract, sealed  (0) 2022.04.08
[C#] 정적 클래스(static class)  (0) 2022.04.08

* abstract

 

- 정의

 

abstract 키워드는 불완전한 클래스나 클래스 멤버를 만들 수 있는 키워드이다. 자식 클래스에서는 이를 무조건 구현해야 한다. 예시는 다음과 같다.

public abstract class A
{
    // Class members here.
}

public abstract class A
{
    public abstract void DoWork(int i);
}

 

 

- 동작 방식

 

abstract는 인스턴스화될 수 없으며 목적은 여러 자식 클래스가 공유하는 부모 클래스의 공통 정의를 제공하는 것이다. 예를 들어 클래스 라이브러리는 abstract 클래스로 정의되고 프로그래머들은 자식 클래스만의 구현을 제공하는 식으로 설계할 수 있다.

 

abstract 클래스는 abstract 메소드도 정의하고 있을 것이다. 예시는 다음과 같다.

public abstract class A
{
    public abstract void DoWork(int i);
}

위 코드와 같이 abstract 메소드는 구현내용이 따로 존재하지 않는다. 자식 클래스는 모든 abstract 메소드를 반드시 구현해야한다.

 

 

abstract 클래스가 다른 클래스를 상속받았을 때 virtual 메소드를 abstract 메소드로 오버라이딩할 수 있다.

// compile with: -target:library
public class D
{
    public virtual void DoWork(int i)
    {
        // Original implementation.
    }
}

public abstract class E : D
{
    public abstract override void DoWork(int i);
}

public class F : E
{
    public override void DoWork(int i)
    {
        // New implementation.
    }
}

abstract 클래스인 E는 D의 구현을 숨기고 F가 virtual 메소드의 구현을 제공하도록 강제한다.

 

 

* sealed

 

- 정의

 

sealed 키워드는 이전 virtual 클래스나 virtual 클래스 멤버의 상속을 방지하는 역할을 한다.

 

 

- 동작 방식

 

sealed 클래스는 부모 클래스가 될 수 없기 때문에 abstract 클래스 역시 될 수 없다. 부모 클래스의 virtual 멤버를 재정의하는 자식 클래스의 메소드 인덱서, 속성, 이벤트 등은 sealed로 지정될 수 있다. 이를 통해 이 후 상속받는 클래스에서 virtual 키워드는 부정된다.

public class D : C
{
    public sealed override void DoWork() { }
}

 

 

'C#' 카테고리의 다른 글

[C#] string vs StringBuilder  (0) 2022.06.28
[C#] Nullable 타입  (0) 2022.06.28
[C#] 값 타입과 참조 타입(Value type, Reference type)  (0) 2022.06.28
[C#] .NET  (0) 2022.06.28
[C#] 정적 클래스(static class)  (0) 2022.04.08

+ Recent posts