형변환(캐스팅) = 어떤 타입의 값을 다른 타입처럼 취급하는 것
예를 들면:
int i = 10;
double d = i; // int → double
이렇게 int 값을 double 변수에 넣는 것도 형변환이다.
C#에서는 크게 이런 종류들이 자주 나온다.
(타입) 캐스팅)is, as)
컴파일러가 “이건 안전하다”라고 보고, 자동으로 해주는 형변환이다.
주로 “작은 타입 → 큰 타입”으로 갈 때 가능하다.
int i = 10;
double d = i; // OK, int → double 자동 변환
int는 4바이트, double은 8바이트int 값은 모두 double로 표현 가능다른 예:
byte b = 100;
int i = b; // OK, byte → int
long l = i; // OK, int → long
float f = l; // OK, long → float (근사값이 될 수 있지만 허용)
한 줄로 정리하면:
“작은 그릇 → 큰 그릇”으로 가는 건 대부분 자동 형변환이 된다.
이번에는 반대로, 개발자가 직접 (타입)을 써줘야 하는 경우다.
주로 “큰 타입 → 작은 타입” 또는 데이터 손실 가능성이 있는 경우에 필요하다.
double d = 3.14;
int i = (int)d; // i는 3 (소수점 잘림)
(int)를 써서 “내가 책임진다”고 표시해야 한다.또 다른 예:
int big = 300;
byte b = (byte)big; // 값이 잘릴 수 있음 (0~255 범위를 넘어서면 값이 뒤틀림)
이런 식으로 데이터가 잘리거나 값이 달라질 수 있는 변환은
반드시 (타입)으로 명시적 캐스팅이 필요하다.
숫자 타입만 형변환이 있는 게 아니다. 클래스/인터페이스 같은 참조 타입도 형변환이 있다.
class Animal
{
public void Eat() => Console.WriteLine("먹는다");
}
class Dog : Animal
{
public void Bark() => Console.WriteLine("멍멍");
}
class Program
{
static void Main()
{
Dog d = new Dog();
Animal a = d; // 업캐스팅: Dog → Animal (묵시적 형변환 가능)
a.Eat(); // OK
// a.Bark(); // 컴파일 에러 (Animal 타입에는 Bark가 없음)
}
}
Dog는 Animal을 상속하므로, Dog는 곧 Animal이다.Animal a = new Dog(); // 실제 인스턴스는 Dog
Dog d = (Dog)a; // 다운캐스팅 (OK)
d.Bark(); // 사용 가능
하지만 이런 경우도 있다:
Animal a = new Animal();
Dog d = (Dog)a; // 컴파일은 되지만, 실행 시 InvalidCastException 발생
a의 실제 인스턴스는 Animal일 뿐, Dog가 아니다.
그래서 C#에서는 안전하게 형 변환을 하기 위해 is와 as를 제공한다.
is, as 연산자is : “이 타입이 맞냐?” 검사Animal a = new Dog();
if (a is Dog)
{
Console.WriteLine("a는 Dog 타입이다");
}
C# 패턴 매칭을 쓰면 이렇게도 가능하다.
if (a is Dog d)
{
d.Bark(); // 여기서 d는 Dog 타입으로 캐스팅된 상태
}
as : 캐스팅 시도, 안 되면 nullAnimal a = new Dog();
Dog d = a as Dog; // 캐스팅 성공 → d는 Dog
if (d != null)
{
d.Bark();
}
Animal a2 = new Animal();
Dog d2 = a2 as Dog; // 캐스팅 실패 → d2는 null
as는 예외를 던지지 않는다.null을 돌려준다.if (d != null) 체크와 같이 사용한다.이건 엄밀히 말하면 “캐스팅”보다는 파싱(Parsing)이지만, 실무에서는 형변환과 같이 다루는 경우가 많다.
string s = "123";
// 문자열 → 숫자
int i1 = int.Parse(s); // 실패 시 예외 발생
int i2;
bool ok = int.TryParse(s, out i2); // 실패해도 예외 없이 false 반환
// 숫자 → 문자열
int n = 456;
string s2 = n.ToString();
Parse, TryParseToString()
C#에서는 모든 타입이 궁극적으로 object를 상속한다.
그래서 int 같은 값 타입도 object로 다룰 수 있는데,
이때 등장하는 개념이 박싱/언박싱이다.
int i = 10;
object o = i; // 박싱 발생
값 타입 i가 힙에 object 형태로 포장되는 느낌으로 이해하면 편하다.
object o = 10; // int 박싱
int i = (int)o; // 언박싱 (명시적 캐스팅 필요)
주의할 점:
object o = 10; // 실제로는 int
double d = (double)o; // 런타임 오류 (InvalidCastException)
o 안에 실제 들어있는 건 int인데,double로 바로 캐스팅하려고 하면 예외가 발생한다.int i = 10; double d = i;(타입)을 써서 개발자가 직접 캐스팅double d = 3.14; int i = (int)d;is, as로 안전하게 검사/캐스팅 가능int.Parse, int.TryParseToString()(int)o 같은 형변환 필요)