[PART2.변수와 기본 데이터 타입(11/13)] 기본 형식 변환 — 암시적·명시적·Parse·TryParse·Convert
목차
- 들어가며
- 변환이란 — 값을 새 옷으로 갈아입히는 일
- 암시적 변환 — 컴파일러가 책임지는 "안전한" 변환
- 명시적 캐스팅 — 개발자가 "책임지겠다" 고 선언하는 변환
- `checked` 와 `unchecked` — 오버플로우를 IL 로 제어하기
- `int.Parse` — 예외로 실패를 알리는 고전적 파서
- `int.TryParse` — 예외 없이 bool 로 실패를 알리는 핫패스 표준
- `Convert.ToInt32` — 다형적 범용 변환기 (그리고 반올림)
- 박싱 / 언박싱 — 값 타입과 참조 타입의 경계를 넘는 일
- 성능과 선택 기준 — 다섯 가지 도구를 언제 쓸까
- Unity 실전 — 형식 변환이 만드는 프레임 스파이크와 GC 압박
- 마무리
들어가며
C# 코드에서 타입이 다른 값을 만났을 때, 우리는 다섯 가지 도구 중 하나를 고릅니다. long total = intValue; 처럼 등호만 써도 되는 경우가 있고, (int)floatValue 처럼 괄호를 박아야 하는 경우가 있고, int.Parse(text) 나 int.TryParse(text, out var n) 처럼 메서드를 호출해야 하는 경우가 있고, Convert.ToInt32(obj) 처럼 범용 클래스를 끼워넣는 경우도 있습니다.
같은 "변환" 이라는 이름으로 묶여 있지만, 이 다섯 가지는 컴파일러가 만들어내는 IL 명령어가 다르고, 실패했을 때의 결과도 다르며, 힙 할당 여부도 다릅니다. 잘못된 선택 하나가 Unity 의 프레임 스파이크가 되기도 하고, 사용자가 오타를 낼 때마다 예외가 뛰어 게임이 버벅이기도 합니다.
이 글은 다섯 가지 도구를 언제 쓰고 왜 그걸 써야 하는지 를 IL 수준에서 증명합니다. 실제 IL 명령어를 디컴파일해 비교하고, checked/unchecked 가 IL 을 어떻게 바꾸는지 보며, Unity 모바일 런타임에서 각 선택이 GC 와 프레임에 미치는 영향을 정리합니다.
1. 변환이란 — 값을 새 옷으로 갈아입히는 일
C# 에서 "형 변환" 이라는 말은 두 가지 전혀 다른 작업을 한 단어로 부르고 있어서 자주 혼란이 생깁니다.
① 비트 패턴을 실제로 바꾸는 변환: int 의 4바이트를 long 의 8바이트로 확장하거나, double 의 8바이트 부동소수점 표현을 int 의 4바이트 정수 표현으로 재배열하는 일입니다. CPU 레벨의 연산이 필요하며, IL 에서 conv.* 명령어 한 줄로 처리됩니다.
② 외부 표현을 내부 표현으로 파싱하는 변환: 문자열 "123" 이라는 유니코드 바이트 시퀀스를 읽어가며 실제로 숫자 123 의 비트 패턴을 만들어내는 일입니다. 이건 단순한 비트 재배열이 아니라 문자를 한 글자씩 해석하는 알고리즘이 돌아가야 하며, IL 에서는 call Int32::Parse(string) 같은 메서드 호출로 표현됩니다.
이 두 가지를 구분하지 못하면 "왜 (int)"10" 은 에러 나는데 (int)10.5 는 되는가?" 같은 질문에 답할 수 없습니다. 숫자 간 변환은 컴파일러의 영역, 문자열 변환은 라이브러리의 영역 이라고 기억하면 됩니다.

2. 암시적 변환 — 컴파일러가 책임지는 "안전한" 변환
암시적(implicit) 변환 은 값의 손실이 절대 없다고 컴파일러가 확신할 수 있을 때 자동으로 수행되는 변환입니다. 개발자가 아무 표시도 하지 않아도 됩니다.
int a = 12345;
long b = a; // 암시적 변환 — 등호만으로 OK
float f = 3.14f;
double d = f; // 암시적 변환 — float → double
작은 상자에 있던 값을 큰 상자로 옮기는 일은 항상 안전합니다. int (4바이트, 약 ±21억 범위) 의 모든 값은 long (8바이트, 약 ±9.2 × 10^18 범위) 에 그대로 들어갑니다. float 의 모든 값은 double 로 정확히 옮길 수 있습니다. 이렇게 값 범위가 부분집합 관계 일 때 C# 스펙은 암시적 변환을 허용합니다.
IL 실측 — conv.i8 한 줄
static long ImplicitIntToLong(int x) => x;
.method private hidebysig static int64 ImplicitIntToLong(int32 x) cil managed
{
IL_0000: ldarg.0
IL_0001: conv.i8
IL_0002: ret
}
ldarg.0: 파라미터x를 스택에 올립니다.conv.i8: 스택 최상단 값을 int64 로 부호 확장 합니다. 원래 32비트 값이었다면 상위 32비트를 부호 비트로 채워 64비트로 만듭니다. CPU 명령어 한 번으로 끝나는 매우 저렴한 작업입니다.ret: 반환.
CPU 입장에서 conv.i8 은 거의 무비용입니다. 레지스터 확장 명령 한 번이면 끝납니다. 그래서 암시적 변환에는 런타임 비용을 걱정할 필요가 없습니다. 부담 없이 씁니다.
주의할 함정 — 부호 있는 / 없는 타입 간 암시적 변환은 없다
int 와 uint 는 둘 다 32비트지만 표현 범위가 달라서 서로 암시적 변환이 되지 않습니다. uint 는 0 ~ 약 42억, int 는 약 -21억 ~ 21억이라, 어느 쪽으로도 손실 없이 옮길 수 없기 때문입니다. 이 경우 반드시 명시적 캐스팅이 필요합니다.
3. 명시적 캐스팅 — 개발자가 "책임지겠다" 고 선언하는 변환
명시적(explicit) 캐스팅 은 손실 가능성이 있을 때 개발자가 (타입) 연산자로 "내가 책임진다" 고 선언하는 변환입니다. 컴파일러는 캐스트 없이는 컴파일 에러를 냅니다.
double pi = 3.14;
int n = (int)pi; // 3 — 소수부가 잘려나감 (truncation, 반올림 아님)
long big = 3_000_000_000L;
int small = (int)big; // 오버플로우 — 의도하지 않은 음수
정수 방향 변환의 결과 를 정확히 기억해야 합니다. (int)3.14 는 3, (int)3.9 도 3, (int)-3.9 는 -3 입니다. 소수부를 반올림하지 않고 그냥 버립니다(truncation). 반올림이 필요하면 Math.Round(d) 또는 Convert.ToInt32(d) 를 써야 합니다 (뒤에서 다룹니다).
IL 실측 — conv.i4 한 줄 (하지만 동작이 다르다)
static int ExplicitDoubleToInt(double d) => (int)d;
.method private hidebysig static int32 ExplicitDoubleToInt(float64 d) cil managed
{
IL_0000: ldarg.0
IL_0001: conv.i4
IL_0002: ret
}
ldarg.0:double값을 스택에 올립니다.conv.i4: 스택 최상단을 int32 로 변환. 원래 타입이double이면 소수부를 버리고 정수부만 취합니다. 원래 타입이long이면 하위 32비트를 취하고 상위 32비트를 그냥 버립니다(오버플로우 검사 없음).ret: 반환.
conv.i4 한 줄에 3.14 → 3 변환과 3_000_000_000 → -1294967296 같은 오버플로우가 모두 들어 있습니다. IL 은 "검사 없이 바이트를 재배열하라" 만 지시하고, 올바른 값이 나오는지는 전적으로 개발자 책임입니다. 이것이 명시적 캐스팅의 본질입니다.

4. checked 와 unchecked — 오버플로우를 IL 로 제어하기
C# 은 기본값이 unchecked 입니다. (int)3_000_000_000L 같은 코드는 런타임에 예외 없이 조용히 잘못된 값을 만들어냅니다. 이는 성능을 위한 선택이지만, 금융 계산이나 게임 점수처럼 "잘못된 값이 절대 들어가서는 안 되는" 곳에서는 위험합니다.
checked 키워드로 해당 블록 안에서만 오버플로우를 감지하게 만들 수 있습니다.
long big = 3_000_000_000L;
int a = (int)big; // unchecked (기본값) → -1294967296 (조용히 손상)
int b = checked((int)big); // checked → OverflowException
IL 실측 — conv.ovf.i4 로 바뀐다
static int CheckedCast(long v) { checked { return (int)v; } }
.method private hidebysig static int32 CheckedCast(int64 v) cil managed
{
IL_0000: ldarg.0
IL_0001: conv.ovf.i4
IL_0002: ret
}
conv.ovf.i4: 오버플로우 감지 기능이 있는 int32 변환 명령. 값이int범위를 넘으면OverflowException을 던집니다. 일반conv.i4에 비해 런타임 검사 한 번이 추가됩니다.
IL 명령어가 conv.i4 에서 conv.ovf.i4 로 완전히 바뀐다는 점이 중요합니다. 컴파일러가 소스의 checked 를 해독해서 다른 IL 명령어를 발행 합니다. 런타임에 플래그를 보고 분기하는 게 아닙니다.
unchecked — 의도적 순환이 필요한 곳
해시 함수나 CRC 계산처럼 오버플로우가 정상 동작 인 코드도 있습니다. 프로젝트 전체 checked 옵션이 켜져 있어도 이런 블록은 unchecked 로 감쌉니다.
unchecked
{
int hash = 17;
hash = hash * 31 + a.GetHashCode();
hash = hash * 31 + b.GetHashCode(); // 곱셈에서 자주 넘치지만 의도된 동작
return hash;
}
5. int.Parse — 예외로 실패를 알리는 고전적 파서
int.Parse(string) 은 문자열을 정수로 해석 하는 메서드입니다. 성공하면 int 를 반환하고, 실패하면 예외를 던집니다.
int a = int.Parse("123"); // 123
int b = int.Parse("abc"); // FormatException
int c = int.Parse("99999999999999"); // OverflowException
int d = int.Parse(null); // ArgumentNullException
세 가지 예외를 기억합니다.
| 입력 | 예외 |
|---|---|
숫자 형식이 아님 ("abc", "1.5", "") |
FormatException |
숫자지만 int 범위 초과 ("99999999999999") |
OverflowException |
null |
ArgumentNullException |
IL 실측 — 평범한 call
static int ParseString(string s) => int.Parse(s);
.method private hidebysig static int32 ParseString(string s) cil managed
{
IL_0000: ldarg.0
IL_0001: call int32 [System.Runtime]System.Int32::Parse(string)
IL_0006: ret
}
IL 자체는 평범합니다. call 로 Int32::Parse 를 호출할 뿐입니다. 성능 비용은 메서드 내부의 문자열 파싱 루프에서, 그리고 실패했을 때 던져지는 예외에서 발생 합니다.
예외의 진짜 비용
C# 에서 throw new FormatException(...) 는 매우 비쌉니다. 예외 객체를 힙에 할당하고, 현재 콜 스택 전체를 훑어서 스택 트레이스를 캡처하고, catch 지점까지 스택을 되감습니다. 일반적인 메서드 호출보다 수백~수천 배 느립니다. 그래서 Parse 는 "실패가 예외적 상황" 일 때만 써야 합니다. 사용자 입력처럼 실패가 일상적인 곳에서는 뒤에 나올 TryParse 를 씁니다.
6. int.TryParse — 예외 없이 bool 로 실패를 알리는 핫패스 표준
int.TryParse(string, out int) 는 예외를 던지지 않는 변환 메서드입니다. 성공 여부는 bool 로 반환하고, 성공했으면 out 파라미터에 결과를 담아 줍니다.
if (int.TryParse("123", out int n))
{
// n == 123
}
else
{
// n == 0 (실패 시 out 은 기본값)
}
실패해도 예외가 없으므로 사용자 입력, 설정 파일, JSON 필드 등 실패가 자주 일어나는 곳에서는 TryParse 가 표준 입니다.
IL 실측 — int32& 는 out 참조
static bool TryParseString(string s, out int n) => int.TryParse(s, out n);
.method private hidebysig static bool TryParseString(string s, [out] int32& n) cil managed
{
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: call bool [System.Runtime]System.Int32::TryParse(string, int32&)
IL_0007: ret
}
int32&:ref int를 의미하는 IL 표기.out키워드는 IL 수준에서는ref와 동일한 참조 전달입니다. 컴파일러가 "호출자가 쓰기 전에 읽지 못하도록" 검증해줄 뿐, 런타임 메커니즘은 같습니다.- 예외를 던지지 않으므로
try/catch가 컴파일될 필요가 없습니다. 실패 시 단순히false를 반환합니다.
Parse 와 TryParse 의 벤치마크적 감각
실패가 드문 경우 (대부분 성공): 두 방식 성능 차이는 거의 없습니다. 성공 시 내부 파싱 로직이 사실상 동일합니다.
실패가 잦은 경우 (예: 10번 중 3번 실패): Parse + try/catch 는 매 실패마다 예외 스택 트레이스 캡처 비용이 발생합니다. TryParse 는 그냥 false 만 반환합니다. 실패율이 1% 만 넘어도 TryParse 가 수십 배 빠릅니다.

7. Convert.ToInt32 — 다형적 범용 변환기 (그리고 반올림)
Convert.ToInt32(...) 는 다양한 입력 타입을 모두 받아서 int 로 변환 하는 범용 메서드입니다. 오버로드가 많습니다.
Convert.ToInt32("123"); // 123 — 내부적으로 int.Parse 호출
Convert.ToInt32(null); // 0 — null 은 0 반환 (Parse 와 다름!)
Convert.ToInt32(true); // 1 — bool → int
Convert.ToInt32(9.8); // 10 — 반올림! (Banker's Rounding)
Convert.ToInt32((object)42); // 42 — object 언박싱
세 가지 핵심 동작 차이를 기억합니다.
① null 은 예외가 아니라 0
int.Parse(null) 은 ArgumentNullException 을 던지지만, Convert.ToInt32(null) 은 그냥 0 을 반환합니다. "null 은 0으로 취급" 이 의도가 맞으면 Convert 가 편리하고, null 을 오류로 봐야 한다면 Parse/TryParse 가 맞습니다.
② 실수 → 정수는 반올림
명시적 캐스팅 (int)9.8 은 9 (절사) 지만, Convert.ToInt32(9.8) 은 10 (반올림) 입니다. 그것도 "Banker's Rounding" (짝수 반올림) 이어서 Convert.ToInt32(2.5) == 2, Convert.ToInt32(3.5) == 4 입니다.
| 입력 | (int) 캐스팅 |
Convert.ToInt32 |
|---|---|---|
| 9.8 | 9 | 10 |
| 2.5 | 2 | 2 (짝수로) |
| 3.5 | 3 | 4 (짝수로) |
| -1.5 | -1 | -2 (짝수로) |
Unity 에서 Input.GetAxis 처럼 float 를 정수화할 때 이 차이가 치명적으로 드러납니다. 뒤에서 다룹니다.
③ object 인자 — 박싱/언박싱 발생
Convert.ToInt32((object)42) 처럼 object 를 받으면 내부에서 IConvertible 인터페이스를 통해 실제 타입을 확인하고 값을 꺼냅니다. 이 과정에서 박싱된 값 타입이 언박싱됩니다. 뒤의 8장에서 구체적으로 분석합니다.
IL 실측 — call 로 끝
static int ConvertToInt(object o) => Convert.ToInt32(o);
.method private hidebysig static int32 ConvertToInt(object o) cil managed
{
IL_0000: ldarg.0
IL_0001: call int32 [System.Runtime]System.Convert::ToInt32(object)
IL_0006: ret
}
IL 자체는 메서드 호출 한 번입니다. 비용은 호출된 메서드 안에서, 박싱된 값을 언박싱하고 타입을 검사하고 변환 테이블을 타는 과정에서 발생합니다.
8. 박싱 / 언박싱 — 값 타입과 참조 타입의 경계를 넘는 일
C# 의 int, float, bool, struct 는 값 타입 으로, 스택에 직접 저장되거나 다른 객체의 필드로 인라인 배치됩니다. 반면 object, string, 클래스 인스턴스는 참조 타입 으로, 힙에 할당되고 스택에는 참조만 들어갑니다.
값 타입을 object 자리에 넣으면 런타임이 힙에 "상자" 를 새로 할당 하고 값을 거기로 복사합니다. 이것이 박싱(boxing) 입니다. 반대로 object 에서 값 타입을 꺼내 스택으로 복사하면 언박싱(unboxing) 입니다.
int v = 42;
object boxed = v; // 박싱 — 힙 할당 + 복사
int unboxed = (int)boxed; // 언박싱 — 타입 검사 + 복사
IL 실측 — box 와 unbox.any
static object BoxInt(int v) => v;
static int UnboxInt(object o) => (int)o;
.method private hidebysig static object BoxInt(int32 v) cil managed
{
IL_0000: ldarg.0
IL_0001: box [System.Runtime]System.Int32
IL_0006: ret
}
.method private hidebysig static int32 UnboxInt(object o) cil managed
{
IL_0000: ldarg.0
IL_0001: unbox.any [System.Runtime]System.Int32
IL_0006: ret
}
box [System.Int32]: 스택의int값을 힙에Int32박스 객체로 할당하고, 그 참조를 스택에 올립니다. 즉, 이 한 줄에 힙 할당 1회 + 값 복사 1회가 들어 있습니다.unbox.any [System.Int32]: 스택의object참조가 실제로Int32박스인지 런타임 타입 검사 를 하고, 맞으면 박스 안의 값을 스택으로 복사합니다. 타입이 틀리면InvalidCastException.
박싱은 new 만큼 비싸며, 힙 할당은 결국 GC 압박으로 돌아옵니다. Unity 모바일에서 박싱이 프레임당 수백 번 일어나면 GC 가 100~200ms 단위로 튀고, 이는 그대로 프레임 스파이크가 됩니다.

9. 성능과 선택 기준 — 다섯 가지 도구를 언제 쓸까
종합하면 다음 표로 결정합니다.
| 상황 | 권장 도구 | 이유 |
|---|---|---|
int → long, float → double 등 확장 |
암시적 변환 | IL 1줄, 무비용 |
double → int 등 절사가 의도된 축소 |
명시적 캐스팅 (int)d |
IL 1줄, 빠름 |
double → int 인데 반올림이 필요 |
Convert.ToInt32(d) 또는 Math.Round → 캐스팅 |
정책 선택 |
| 금융·점수 등 오버플로우 감지 필수 | checked((int)x) |
conv.ovf.i4 로 예외 |
| 해시·CRC 등 의도적 순환 | unchecked 블록 |
예외 억제 |
| 형식이 보장된 문자열 (설정 파일, 상수) | int.Parse |
간결, 실패는 버그 |
| 사용자 입력, 외부 데이터 | int.TryParse |
예외 비용 회피 |
object, null, 다양한 타입을 함께 처리 |
Convert.ToInt32 |
범용성, null→0 |
값 타입을 object 에 담기 |
가급적 피하기 (제네릭·in 파라미터로 회피) |
박싱 = 힙 할당 |
핫패스에서 string → int 1000번 반복 (개념적 비용)
- 성공만 하는 경우:
Parse≈TryParse(내부 로직 동일) - 5% 실패하는 경우:
TryParse가Parse+try보다 대략 10~20배 빠름 (예외 스택 트레이스 비용) - 50% 실패하는 경우:
TryParse가Parse+try보다 100배 이상 빠름
정확한 숫자는 런타임 버전·JIT·스택 깊이에 따라 다르지만, 방향성은 위와 같이 단조증가 합니다.
10. Unity 실전 — 형식 변환이 만드는 프레임 스파이크와 GC 압박
① 사용자 입력은 무조건 TryParse
InputField 로 받은 문자열에 Parse 를 쓰면, 사용자가 빈 문자열이나 오타를 낼 때마다 예외가 뛰면서 프레임이 튑니다. 모바일에서는 특히 심각합니다.
DO:
public InputField scoreInput;
public void OnSubmit()
{
if (int.TryParse(scoreInput.text, out int score))
{
ApplyScore(score);
}
else
{
ShowToast("숫자만 입력해주세요");
}
}
DON'T:
// 사용자가 "abc" 를 치면 예외 + 스택 트레이스 캡처 → 모바일에서 프레임 스파이크
try
{
int score = int.Parse(scoreInput.text);
ApplyScore(score);
}
catch (FormatException)
{
ShowToast("숫자만 입력해주세요");
}
② Input.GetAxis → 타일 좌표: 절사와 반올림의 차이
Input.GetAxis("Horizontal") 는 -1.0f ~ 1.0f 의 float 입니다. 이를 타일 단위 이동 -1, 0, +1 로 만들 때, 명시적 캐스팅은 조작감을 크게 떨어뜨립니다.
float h = Input.GetAxis("Horizontal"); // 0.7f
int a = (int)h; // 0 — 절사! 사용자가 반쯤 기울여도 정지
int b = Mathf.RoundToInt(h); // 1 — 반올림, 자연스러움
int c = (int)Mathf.Sign(h); // 1 — 부호만 취함, 격자 이동에 적합
DO:
// 타일 격자 이동 — 부호만 쓰는 게 가장 명확
int dir = 0;
float h = Input.GetAxis("Horizontal");
if (Mathf.Abs(h) > 0.1f) dir = (int)Mathf.Sign(h);
DON'T:
// 0.7 이 0 이 되므로 키를 반만 기울이면 "정지"
int dir = (int)Input.GetAxis("Horizontal");
③ 세이브/로드 — Dictionary<string, object> 는 박싱 지옥
게임 데이터를 유연하게 짠다고 Dictionary<string, object> 에 gold = 100, hp = 80 을 넣으면, 값 타입이 모두 박싱 됩니다. 꺼낼 때마다 언박싱까지 발생합니다.
// DON'T — 박싱 + 언박싱이 프레임마다 발생
private Dictionary<string, object> save = new();
save["gold"] = 100; // box [Int32] → 힙 할당
int gold = (int)save["gold"]; // unbox.any [Int32]
DO — 타입이 명시된 클래스로 직렬화:
[System.Serializable]
public class SaveData
{
public int gold;
public int hp;
public float moveSpeed;
}
string json = JsonUtility.ToJson(saveData);
File.WriteAllText(path, json);
SaveData loaded = JsonUtility.FromJson<SaveData>(File.ReadAllText(path));
// 박싱 없음, 필드는 값 타입 그대로
④ Convert.ToInt32(obj) 는 피하기
SerializedData 나 Reflection 으로 object 를 받는 경우에도, 호출마다 박싱/언박싱이 섞이면 GC 가 튑니다. 가능한 한 제네릭 API 를 쓰거나 (JsonUtility.FromJson<T> 등), 타입 체크 후 직접 캐스팅 하는 쪽이 낫습니다.
// 덜 나쁨
if (value is int i) UseInt(i);
// 최악 (object 받는 순간 박싱 확정, 꺼낼 때 언박싱)
int i = Convert.ToInt32(value);
⑤ checked 는 릴리즈 빌드에서 "감지 필요한 곳만"
Unity 모바일 릴리즈 빌드에서 프로젝트 전체 checked 옵션을 켜면 모든 산술이 conv.ovf.* 로 바뀝니다. 검증되지 않은 범위 초과를 잡기엔 좋지만, 핫루프에서는 성능 손실이 쌓입니다. 점수·결제 등 오버플로우가 곧 버그인 지점에만 checked((int)v) 로 명시 하는 쪽이 실무적으로 안전합니다.
마무리
형식 변환은 언뜻 "그냥 되는 것" 처럼 보이지만, IL 한 줄 차이가 런타임에서는 힙 할당 1회, 예외 1회, 반올림 정책 1가지의 차이로 쌓입니다.
- 숫자 확장 은 암시적 변환 —
conv.i8한 줄, 무비용. - 숫자 축소·실수→정수 는 명시적 캐스팅 —
conv.i4, 절사 임을 잊지 않기. - 오버플로우 감지가 필요한 캐스팅 은
checked—conv.ovf.i4로 바뀜. - 형식이 보장된 문자열 은
int.Parse— 실패는 버그. - 사용자 입력·외부 데이터 는
int.TryParse— 예외 비용 회피. - null·다양한 타입 섞인 범용 변환 은
Convert.ToInt32— 단, 반올림·박싱 주의. - 값 타입 ↔ object 는
box/unbox.any— Unity 모바일에서 GC 의 주범, 제네릭으로 우회.
다음 글에서는 이 기본 타입들이 묶여서 배열과 컬렉션이 되는 과정을 살펴봅니다.
'C# 기초' 카테고리의 다른 글
| [PART2.변수와 기본 데이터 타입(13/13)] nullable 참조 타입(NRT) — `string?`과 null 안정성 (C# 8) (0) | 2026.04.24 |
|---|---|
| [PART2.변수와 기본 데이터 타입(12/13)] default 리터럴과 값 타입 nullable (Nullable<T>) (0) | 2026.04.24 |
| [PART2.변수와 기본 데이터 타입(10/13)] 상수 문자열 보간 — const 문자열에 $"..." 허용 (C# 10) (0) | 2026.04.24 |
| [PART2.변수와 기본 데이터 타입(9/13)] 상수 — const와 readonly (2) | 2026.04.24 |
| [PART2.변수와 기본 데이터 타입(8/13)] var — 타입 추론의 기본 사용법 (1) | 2026.04.24 |