멈추지 않고 끈질기게
[C#] 형변환 함수 / 연산자 본문
※ 해당 포스팅은 개인의 공부 정리용 글입니다. 틀린 내용이 있다면 추후 수정될 수 있습니다.
※ 해당 포스팅은 .Net 7.0 버전을 기준으로 작성되었습니다.
0. 서문
변수 앞에 (타입명)을 붙이는 형변환 방식은 단순하고 강력하지만 그만큼 잘못된 형변환으로 인한 위험 부담도 동반합니다. 이를 막기 위해 C++의 경우 4종류의 타입 변환 연산자를 제공합니다(static_cast<T>, dynamic_cast<T>, reinterpret_cast<T>, const_cast<T>). C#에서도 이와 비슷하게 명시적 형변환을 위한 수단을 제공하고 있습니다.
1. Convert 클래스
C#에서는 명시적 형변환을 위한 함수들이 정의되어 있는 Convert 클래스를 제공합니다. 해당 클래스에는 'To(타입명)'과 같은 이름의 함수들이 정의되어 있으며, 각 함수들은 다양한 타입의 매개변수를 받을 수 있도록 여러개의 함수로 오버로딩되어 있습니다. 다음은 비쥬얼 스튜디오에서 Convert.ToByte() 함수의 정의부를 확인한 것입니다.
따라서 기본적인 타입들의 형변환은 Convert 클래스의 함수들을 사용하는 것이 바람직합니다. 다음은 Convert 클래스의 사용 예시입니다.
int num1 = Convert.ToInt32(12.34f);
long num2 = Convert.ToInt32(56.78f);
byte num3 = Convert.ToByte(false);
string s1 = Convert.ToString(123);
string s2 = Convert.ToString(789);
Console.WriteLine($"num1: {num1}");
Console.WriteLine($"num2: {num2}");
Console.WriteLine($"num3: {num3}");
Console.WriteLine($"s1 + s2: {s1 + s2}");
참고로 소수를 정수형으로 변경하는 경우 기본적으로 소수점 첫째자리에서 반올림합니다. 12.34f의 경우 버림 처리되어 12가 되고, 56.78f의 경우 올림 처리되어 57을 출력하는 모습을 볼 수 있습니다.
또한 형변환이 불가능한 매개변수를 전달할 경우 예외가 발생할 수 있습니다. 예를 들어 Convert.ToChar() 함수에 두글자 이상의 문자열을 전달할 경우, FormatException이 발생하므로 주의해야 합니다.
// 잘못된 형변환 예시
// 2글자 이상의 문자열을 char 변환 시도
char c = Convert.ToChar("ASDF");
2. 문자열의 타입 변환
string을 제외한 대부분의 기본 타입들은 Parse()함수를 가지고 있습니다. 해당 함수를 통해 문자열에서 다른 타입으로의 형변환이 가능합니다. 다음은 Parse() 함수의 사용 예시입니다.
int num1 = int.Parse("1234");
float num2 = float.Parse("56.78");
bool isTrue = bool.Parse("true");
if (isTrue)
{
Console.WriteLine($"num1 + 50 = {num1 + 50}");
Console.WriteLine($"num2 * 2 = {num2 * 2}");
}
isTrue 변수가 true로 초기화되어 num1, num2로 연산한 결과를 출력하는 모습입니다. Parse() 함수도 Convert 클래스의 함수들과 마찬가지로 형변환이 불가능한 경우 FormatException을 발생시키므로 주의해야 합니다. 예를 들어 bool.Parse() 함수의 경우 대소문자는 구분하지 않지만, true나 false 외의 문자열을 매개변수로 넣을 경우 FormatException이 발생합니다.
// Parse()의 잘못된 사용 예시
bool isFalse = bool.Parse("fail");
3. as 연산자
as 연산자는 클래스 타입간의 형변환을 처리하는 연산자입니다. C++의 dynamic_cast<T> 연산자와 기능이 비슷하며, 해당 형변환이 정상적으로 이루어지지 않을 경우 null을 반환합니다. 다음은 as 연산자의 사용 예시입니다.
// 테스트용 상속 관계의 클래스 선언
class Weapon
{
}
class Sword : Weapon
{
}
Weapon w1 = new Weapon();
Sword s1 = new Sword();
// null값 허용을 위해 ? 연산자 사용
Weapon? w2 = s1 as Weapon;
Sword? s2 = w1 as Sword;
if(w2 != null)
Console.WriteLine("Sword -> Weapon 변환 성공!");
else
Console.WriteLine("Sword -> Weapon 변환 실패...");
if (s2 != null)
Console.WriteLine("Weapon -> Sword 변환 성공!");
else
Console.WriteLine("Weapon -> Sword 변환 실패...");
부모(Weapon) 타입의 변수 w2를 자식(Sword) 타입의 변수 s1을 as 연산자로 변환하여 초기화하고, 자식 타입의 변수 s2를 부모 타입의 변수 w1을 as 연산자로 변환하여 초기화했습니다. w2의 경우 자식->부모로의 형변환이므로 성공했지만, s2의 경우 부모->자식으로의 형변환이므로 실패하여 null값으로 초기화된 것을 알 수 있습니다. 이렇게 클래스간의 형변환은 as 키워드를 사용한 후 null 체크를 통해 성공 여부를 확인하여 좀 더 안전하게 실행할 수 있습니다.
4. 결론
사실 포트폴리오를 만들면서 습관적으로 '(int)변수명'과 같은 식으로 강제 형변환을 하는 경우가 꽤 있었습니다. 형변환에 관한 내용을 정리하고 보니 안좋은 습관은 고쳐야겠습니다. 앞으로는 가급적이면 명시적 형변환을 하는 습관을 들이고자 합니다.
'C#' 카테고리의 다른 글
[C#] C# 9.0 기능(record 타입, 초기화 전용 속성(init), 타겟 타이핑(new(), 조건 연산자)) (0) | 2023.10.09 |
---|---|
[C#] 열거형(Enum) (0) | 2023.06.28 |
[C#] StringBuilder (0) | 2023.02.20 |
[C#] 가비지 컬렉터(Garbage Collector) (0) | 2023.02.20 |
[C#] Linq 구문 (0) | 2023.02.18 |