기본 자료형
-
Value Type
UTF-16 인코딩은 common language runtime에서 Char 및 String 값을 나타내는 데 사용되며 Windows 운영 체제에서 WCHAR 값을 나타내는 데 사용된다.
-
기본 자료형의 default value
값 형식을 가리키는 변수는 해당 자료형에 대해 무조건 메모리가 할당되므로 그 메모리 영역에 필연적으로 기본값을 갖게 된다. 닷넷은 자료형에대한 메모리를 할당하면 해당 영역을 무조건 0으로 초기화 한다.
value type vs. reference type
-
Value types and reference types in the CTS
위의 그림과 같이 CTS에서 변수는 참조형식, 값형식으로 나뉜다. 값형식에 속하는 것으로는 sbyte, byte, char, short, ushort, int, uint, long, ulong, float, double, decimal, bool이, 참조형식에 속하는 것으로는 string, 배열, 클래스, object이 있다.
object는 그 자체가 참조형임에도 값 형식의 부모 타입이기도 하다. 참조 형식과 값 형식은 처리 방식이 매우 다른데, 이러한 불일치를 구분하기 위해 닷넷에서는 모든 값 형식을 System.ValueType타입에서 상속받게 하고 있으며, 다시 System.ValueType은 object를 상속받고 있다. 즉, 값 형식은 System.ValueType으로부터 상속받은 모든 타입을 의미하고, 참조 형식은 object로부터 상속받은 타입 가운데 System.ValueType의 하위 타입을 제외한 모든 타입을 의미한다.
값/참조 형식의 차이점을 이해하려면 반드시 스택(Stack)과 힙(Heap)을 이해할 필요가 있다.
stack 윈도우 프로그램은 기본적으로 하나의 스레드를 갖는다. 그리고 개별스레드마다 전용으로 사용할 수 있는 저장소가 메모리에 할당되는데 그 영역을 스택이라고 한다. 스택은 기본적으로 1MB공간만 스레드에 할당한다. 1MB라는 용량은 일반적인 메서드 호출 상황에서 스택 오버플로를 발생시키기에는 여유가 있는 공간이다. 하지만 재귀 호출을 사용하는 프로그램에는 문제가 발생할 수 있다.
heap 힙은 프로그램에서 필요에 의해 메모리를 사용하겠다고 요청했을 때 사용할 수 있는 저장소다. 힙의 경우 별도로 명시하지 않는 한 CLR에서는 관리 힙(managed heap)을 가리킨다. 관리 힙이란 CLR의 가비지 수집기(GC:Garbage Collector)가 할당/해제를 관리하기 때문에 붙여진 이릅이다. C#에서 new로 할당되는 모든 참조형 객체는 힙에 할당된다. 메모리 해제는 GC가 자동으로 해준다.
* **스택에 저장된 값 형식의 데이터**


- 값 형식과 참조 형식의 차이점

박싱 / 언박싱
박싱 : 값 형식 -> 참조 형식 언박싱 : 참조 형식 -> 값 형식
static void Main(string[] args)
{
int a = 5;
int b = 6;
object obj = a; // 박싱 : 값 형식인 int를 참조 형식인 object에 대입
int c = GetMaxValue(a, b);// 언박싱
}
박싱이 빈번할 수록 GC는 바빠지고 프로그램의 수행 성능은 그만큼 떨어진다. 따라서 박싱을 과다하게 발생할 수 있는 코드는 최대한 줄이는 것을 권장한다.
var
C#3.0 컴파일러부터는 타입 추론(type inference)기능이 추가되면서 메서드의 지역 변수 선언을 타입에 관계없이 var 예약어로 쓸 수 있게 됐다.
static void Main(string[] args)
{
int i = 5;
var j = 6;
List<int> number1 = new List<int>(new int[] {1, 2, 3, 4, 5});
List<int> number2 = new List<int>(new int[] {6, 7, 8, 9, 10});
Dictionary<string, List<int>> dict = new Dictionary<string, List<int>>();
foreach (KeyValuePair<string, List<int>> elem in dict)
{
}
}
foreach문에서 컬렉션의 요소 타입을 지정하는 것이 복잡하다. 이때 var 예약어를 이용하면 코드가 더 간결해진다.
foreach (var elem in dict)
{
}
Nullable
bool 타입은 true/false값만을 가질 수 있는데, Nullable타입은 일반적인 값 형식에 대해 null표현이 가능하게 하는 역할을 한다. Nullable Type은 두 가지 방법으로 선언될 수 있다.
System.Nullable<T> variable;
//-or-
T? variable;
T는 Nullable type의 underlying type이다. reference type을 제외한 struct를 포함하는 모든 value type은 T가 될 수 있다.
Nullable<int> intValue = 10;
int? n = null;
//int m1 = n; // Will not compile.
int m2 = (int)n; // Compiles, but will create an exception if n is null.
int m3 = n.Value; // Compiles, but will create an exception if n is null.
구조체
값 형식에도 class처럼 사용자 정의 형식을 둔 것이 구조체이다.
- 인스턴스 생성을 new로 해도 되고, 안 해도 된다.
- 기본 생성자는 명시적으로 정의할 수 없다.
- 매개변수를 갖는 생성자를 정의해도 기본 생성자가 C#컴파일러에 의해 자동으로 포함된다(클래스의경우에는 포함되지 않는다).
- 매개변수를 받는 생성자의 경우, 반드시 해당 코드 내에서 구조체의 모든 필드에 값을 할당해야 한다.
구조체 인스턴스를 new로 생성하는 것은 아래와 같다.
Vector v1 = new Vector();
Vector v2;
v2.x = 0;
v2.y = 0;
Vector v3 = new Vector(0,0);

제어문
-
foreach문
in 다음에 오는 배열을 처음부터 끝까지순회하면서 개별 요소를 변수명에 넣어 반복문 구문 내에서 해당 변수를 사용할 수 있게 해준다.
//foreach (표현식요소의_자료형 변수명 in 표현식)
//구문;
- switch문

연산자
-
as 연산자 as 연산자는 nullable types과 reference types간의 type conversion을 수행하는 연산자다. 기본적으로 as 연산자는 cast 연산자와 같지만 conversion이 불가능할경우 exception을 발생시키는 대신 null값을 반환한다.
class csrefKeywordsOperators
{
class Base
{
public override string ToString()
{
return "Base";
}
}
class Derived : Base
{ }
class Program
{
static void Main()
{
Derived d = new Derived();
Base b = d as Base;
if (b != null)
{
Console.WriteLine(b.ToString());
}
}
}
}
- is 연산자
if (obj is MyObject)
{
}
is 연산자는 obj가 MyObject type 또는 MyObject를 상속받은 type이면 true를 반환하고 다른 경우 false를 반환한다.
class Class1 {}
class Class2 {}
class Class3 : Class2 { }
class IsTest
{
static void Test(object o)
{
Class1 a;
Class2 b;
if (o is Class1)
{
Console.WriteLine("o is Class1");
a = (Class1)o;
// Do something with "a."
}
else if (o is Class2)
{
Console.WriteLine("o is Class2");
b = (Class2)o;
// Do something with "b."
}
else
{
Console.WriteLine("o is neither Class1 nor Class2.");
}
}
static void Main()
{
Class1 c1 = new Class1();
Class2 c2 = new Class2();
Class3 c3 = new Class3();
Test(c1);
Test(c2);
Test(c3);
Test("a string");
}
}
//Output:
//o is Class1
//o is Class2
//o is Class2
//o is neither Class1 nor Class2.