프로그래밍에서 특정 형식의 데이터를 다른 형식으로 형 변환하는 경우는 흔한 일중 하나입니다. 예를 들어 사용자로부터 입력받은 값은 string형식인데 해당 값을 사칙연산으로 계산하기 위해 int형식으로 바꾸는 경우입니다.
※ 형 변환을 언급할 때 Casting과 Convert라는 말이 자주 사용되는데 이 둘은 같은 의미를 가집니다.
형 변환이 크게 명시적인 형태와 명시적인 형태 이 2가지로 이루어집니다. 암시적인 형 변환은 대부분 자동적으로 변환되는 것으로 기존에 변수가 가진 값의 손실이 없이 완벽하게 변환되는 경우로 안전하게 처리될 수 있습니다. 하지만 명시적인 형변환은 직접 형 변환을 코드로 구현해 처리하는 것으로 이런 경우는 상황에 따라 기존 값의 일부 손실이 있을 수 있습니다.
● 숫자 형식에 대한 명시적 형 변환과 암시적 형변환
암시적인 형 변환은 알아서 자동적으로 형 변환이 이루어 지는 경우로 주로 범위가 작은형식에서 더 큰형식으로의 형변환의 경우를 말합니다. 예를 들어 int형에서 douoble형으로의 변환과 같은 경우로 이런 경우는 형변환과정에서 기존 데이터의 손실이 발생하지 않기 때문에 안전하게 형변환이 처리될 수 있습니다.
int i = 10;
double d = i; //암시적인 형변환
Console.WriteLine(d);
//10
하지만 반대의 경우라면 예를 들어 위의 예제와 같은 경우 double을 int형으로 형 변환을 하려면 명시적으로 형변환을 지시해야 합니다. 물론 이렇게 형 변환이 이루어지는 경우 기존 데이터의 정밀 도면에서 손실이 발생되는걸 개발자가 알고 있다는 전재로 이루어집니다.
double d = 10.9;
int i = (int)d; //명시적인 형변환
Console.WriteLine(i);
//10 -> 0.9값이 손실됨
● System.Convert 사용하기
이전 예제에서 명시적인 형 변환의 경우 변환하고자 하는 type을 괄호를 사용해 '(int)'처럼 명시하였습니다. 이것을 '형 변환 연산자'라고도 하는데 이렇게 하는 대신 System.Convert를 사용하여 형 변환을 수행할 수도 있으며 실제 이 방법을 더 권장하기도 합니다. 또한 System.Convert는 단순 number형식뿐만 아니라 bool, string, datetime등 다양한 형식에서도 형변환을 수행할 수 있습니다.
double d = 10.9;
int i = Convert.ToInt32(d); //명시적인 형변환
Console.WriteLine(i);
//11 -> 반올림처리
C#에서 반올림/반내림 규칙은 일반적으로 소수점 이하 부분이 .5보다 크면 반올림을 .5보다 작으면 반내림을 적용하지만 정확히 .5가 되는 경우에는 정수 부분이 홀수인 경우 반올림을, 짝수인 경우 반내림을 수행하므로 이 부분에 주의가 필요합니다.
double d1 = 9.5; //9는 홀수 -> 반올림10
double d2 = 10.5; //10은 짝수 -> 반내림10
int r1 = Convert.ToInt32(d1);
int r2 = Convert.ToInt32(d2);
Console.WriteLine($"{r1}, {r2}");
이러한 규칙은 반올림이나 반내림이 한쪽으로만 기울어지는 걸 방지하는 효과를 가지게 되므로 나름대로의 균형을 잡는데 선호되는 규칙입니다.(다만 모든 언어가 해당 규칙을 따르지는 않습니다.)
물론 필요하다면 정수 부분의 짝수/홀수와는 상관없이 다음과 같은 방법으로 .5이상인 경우는 무조건 반올림을 .5미만인 경우 무조건 반내림으로 처리될 수 있도록 지정할 수 있습니다.
double d1 = 9.5; //9는 홀수 -> .5이므로 10
double d2 = 10.5; //10은 짝수 -> .5이므로 11
double r1 = Math.Round(d1, 0, MidpointRounding.AwayFromZero);
double r2 = Math.Round(d2, 0, MidpointRounding.AwayFromZero);
Console.WriteLine($"{r1}, {r2}");
● string으로의 변환
모든 type은 System.Object로부터 상속되므로 해당 Object가 가진 ToString()이라는 메서드를 사용하여 특정 변수의 현재 값을 string형식으로서 표현할 수 있습니다. 만약 값을 표현하지 않는 type이라면 자신의 Namespace와 Type명을 문자열로 반환합니다.
int i = 10;
double d = 10.98;
object o = new();
Console.WriteLine(i.ToString()); //10
Console.WriteLine(d.ToString()); //10.98
Console.WriteLine(o.ToString()); //System.Object
만약 변환 대상이 Image나 Video 같은 binary형식인 경우 bit를 있는 그대로 다루는 대신 어떤 이유에서든 문자열로 변환해야 하는 경우가 발생할 수 있고 이런 경우라면 Base64 형식의 인코딩을 활용할 수 있습니다.
위에서 언급한 System.Convert는 이를 위해 ToBase64 String() 메서드와 FromBase64 String() 메서드를 가지고 있으며 To는 String으로의 변환을 From은 String에서 binary로의 변환을 수행합니다.
System.Drawing.Image img = pictureBox1.Image;
MemoryStream ms = new();
img.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
byte[] b = ms.ToArray();
string s = Convert.ToBase64String(b);
/////////////////////////////////////////////////////
byte[] cb = Convert.FromBase64String(s);
MemoryStream cms = new MemoryStream(cb);
System.Drawing.Image cimg = Image.FromStream(cms);
pictureBox2.Image = cimg;
위 예제는 pictureBox1에 있는 이미지를 가져와 Base64로 인코딩한 뒤 그 결과를 다시 byte로 변환하여 pictureBox2의 이미지로 출력합니다. 실제 pictureBox1의 이미지를 pictureBox2라는 WinForm컨트롤의 이미지로 복사하기 위해 위와 같은 복잡한 과정을 거칠 필요는 없지만 Base64의 인코딩과 디코딩이 어떻게 사용될 수 있는지를 보여주기 위한 것으로는 충분할 것입니다.
● string에서 다른 형식으로의 변환
단순 문자열을 통해서는 정수 값은 물론 날짜나 시간과 같은 형식의 표현도 가능합니다.
string i = "10"; //정수 10
string d = "2021-03-03"; //날짜
하지만 어디까지나 문자열일 뿐이므로 해당 데이터를 정확히 다루려면 적절한 형식으로 변환을 해야 하는데 C#에서의 몇몇 Type은 이를 위해 Parse()라는 메서드를 가지고 있습니다.
string si = "10";
int i = int.Parse(si);
Console.WriteLine(i); //10
string di = "2022-03-18";
DateTime d = DateTime.Parse(di);
Console.WriteLine($"{d:D}"); //2022년 3월 18일 금요일
참고로 예제에서 사용된 D는 DateTime값에서 날짜와 요일만을 표시하기 위한 것입니다. 자세한 사항은 아래 링크를 참고하시기 바랍니다.
Standard date and time format strings | Microsoft Docs
Parse() 메서드는 문자열에서 필요한 데이터 형식으로의 변환을 간단하게 수행할 수 있지만 잘못된 문자열이 존재하는 경우는 Runtime에러를 유발할 수 있습니다. (Convert로 변환을 수행하지만 동일하게 Runtime에러가 발생할 수 있습니다.)
string s = "abc";
int i = int.Parse(s);
Console.WriteLine(i);
/*
Unhandled exception. System.FormatException: Input string was not in a correct format.
at System.Number.ThrowOverflowOrFormatException(ParsingStatus status, TypeCode type)
at System.Int32.Parse(String s)
at Program.<Main>$(String[] args) in C:\Users\Administrator\Downloads\csharp\Program.cs:line 10
*/
이런 불완전한 상황을 피하려면 Parse() 대신 TryParse() 메서드를 사용하길 권장합니다.
string s = "abc";
bool b = int.TryParse(s, out int i);
if (b == true)
{
Console.WriteLine($"변환성공 : {i}");
}
else
{
Console.WriteLine("변환실패");
}
TryParse는 주어진 값이 해당 형식으로의 변환이 가능하다면 true를 그럴 수 없다면 false를 반환하므로 이를 통해 사전에 변환이 가능한지를 판단할 수 있습니다. 만약 변환이 가능해 true값을 얻게 된다면 out 매개변수로 지정한 변수에 해당 값을 저장합니다.
'.NET > C#' 카테고리의 다른 글
[C#] C#과 OOP(Object-Oriented Programming) - 1. 객체지향프로그래밍 개념 (0) | 2022.06.24 |
---|---|
[C#] 예외처리 (0) | 2022.06.24 |
[C#] 흐름제어 (0) | 2022.06.24 |
[C#] 연산자 (0) | 2022.06.24 |
[C#] C# 개요 - 3. 기타 Console Application 관련 (0) | 2022.06.24 |