cast는 객체를 가져와 유형 변경이 허용되는 경우 지정된 유형의 객체로 변경하도록 "강제" 하는거다. 캐스팅하려면 값 옆의 괄호 안에 대상 유형을 배치하여 값을 캐스팅한다.
public static void Main(string[] args)
{
int val = 1;
var doubleVal = (double)val; // cast an int to a double
Console.WriteLine(doubleVal); // output: 1
char cval = 'a';
var intVal = (int)cval; // cast a char to a int
Console.WriteLine(intVal); // output: 97
float fval = 4.56F;
decimal decimalVal = (decimal)fval;
Console.WriteLine(decimalVal); // output: 4.56
decimal dval = 5.87M;
int lostIntVal = (int)dval;
Console.WriteLine(lostIntVal); // output: 5(.87값이 사라짐)
string sval = "Hello";
byte byteVal = (byte)sval; // Syntax Error(컴파일 오류 발생)
}
주의해야 할점은 4번째 코드처럼 decimal을 int로 변환시 소수점 아래 값이 사라지게 된다. 따라서 정확한 유형(예: 부동 소수점 숫자 유형)을 int, long, char등으로 변환할 때 주의해야 한다.
convert는 cast와 유사하게 다른 유형의 객체로 변경한다는 점에서 캐스트와 유사하고 캐스트보다 더 유연하지만 실행하는 계산적으로는 더 오래 걸린다.
public static void Main(string[] args)
{
int a = 1;
decimal b = Convert.ToDecimal(a);
Console.WriteLine(b); // output: 1
decimal c = 5.6M;
int d = Convert.ToInt32(c);
Console.WriteLine(d); // output: 6
decimal e = 5.4M;
int f = Convert.ToInt32(e);
Console.WriteLine(f); // output: 5
decimal g = 5.5M;
int h = Convert.ToInt32(g);
Console.WriteLine(h); // output: 6
decimal i = 4.5M;
int j = Convert.ToInt32(i);
Console.WriteLine(j); // output: 4
}
convert는 cast와 달리 부동소수점 자리에 대한 처리가 유연하다. 위 코드에서 변수 c를 int로 convert하면 반올림된 6으로 변환된다. 하지만 변수 e를 int로 convert하면 소수점이 버려지고 5로 변환되며, 변수 g와 i는 각각 6과 4로 변환된다.
convert는 값은 대신 "banker's rounding"이라는 방법을 사용하여 가장 가까운 정수로 반올림된다. 숫자가 정확히 두 정수 사이의 중간, 즉, X.5이면 짝수가 반환된다.(예: 숫자가 4.5이면 4를 반환, 5.5이면 6을 반환) 그렇지 않으면 가장 가까운 정수로 반올림한다.
convert와 cast의 가장 큰 차이는 convert클래스는 숫자에서 숫자가 아닌 변환 및 그 반대로의 변환을 처리할 수 있다.
public static void Main(string[] args)
{
// convert vs cast
string k = "5.0";
decimal l = Convert.ToDecimal(k); // output: 5.0
decimal m = (decimal)k; // syntax error
int n = 5;
string o = Convert.ToString(n); // output: "5"
string p = (string)n; // syntax error
int q = 1;
bool r = Convert.ToBoolean(q); // output: True
bool s = (bool)q; // syntax error
}
C#에서 string은 참조 유형으로 다른 유형으로 변환할 때 특별한 처리가 필요하는데 이것을 파싱이라고 한다. .NET Framework는 해당 형식으로의 변환을 처리하기 위해 각 기본 형식에 대해 Parse() 메서드를 제공한다.
public static void Main(string[] args)
{
string a = "1.1";
decimal b = decimal.Parse(a); // output: 1.1
string c = "Hello";
int d = int.Parse(c); // runtime error(System.FormatException)
}
그러나 string을 허용되는 값으로 구문 분석할 수 없는 경우 Parse() 메서드는 예외를 throw 한다.
string을 원하는 유형으로 구문 분석할 수 있는지 여부를 알 수 없는 상황에서 사용하는 메서드이다.
public static void Main(string[] args)
{
string a = "1.1";
bool c = decimal.TryParse(a, out decimal b); // output: c - true, b - 1.1
string d = "Hello";
bool f = int.TryParse(d, out int e); // output: f - false, e - 0
}
Parse와 다르게 string을 허용되는 값으로 구문 분석할 수 없는 경우 TryParse() 메서드는 false를 반환한다.
주어진 객체의 특정 유형을 모르는 경우(외부 데이터베이스, API 또는 서비스와 같은 다른 소스에서 개체를 검색한 경우) is는 개체가 특정 유형인지 테스트하는 키워드이다.
public static void Main(string[] args)
{
var a = 1.1M;
if(a is int)
{
Console.WriteLine("This is integer.");
}
else if(a is string)
{
Console.WriteLine("This is string.");
}
else if(a is decimal)
{
Console.WriteLine("This is decimal.");
}
// output: This is decimal.
}
as도 캐스팅을 하는 키워드로 참조 타입간의 캐스팅만 가능하고 값 형식의 타입의 변환은 안된다. 위에서 본 캐스팅 연산자들이 변환에 실패하는 경우 예외를 던지는 반면 as 연산자는 null을 반환한다.
internal class Program
{
public static void Main(string[] args)
{
Parent p = new Child();
Child p2 = p as Child;
if(p2 != null)
{
p2.ChildItem();
}
// output: Child Item
}
}
class Parent
{
public void ParentItem()
{
Console.WriteLine("Parent Item");
}
}
class Child : Parent
{
public void ChildItem()
{
Console.WriteLine("Child Item");
}
}
Parent 객체가 Child 형으로 선언되었고 Parent 객체를 Child 형식으로 캐스팅하여 null인지 체크한 뒤 Child 클래스 내부의 메서드를 호출한다.