본문 바로가기
Study

C#, 일반적인 Cast와 is, as 키워드 그리고 퍼모먼스

by Client. DJ 2022. 1. 13.
반응형

프로그래밍 언어 공부 중 형변환을 사용한다면 보편적으로 일반적인 Cast 방식을 사용합니다.

private static void Main(string[] args)
{
	int intValue = 0;
	long longValue = 2147483647;   // = int.MaxValue
	intValue = (int)longValue;
	Console.WriteLine(intValue);

	// Result
	// 2147483647
}

위와 같은 방식으로 long형에서 int형으로 데이터형이 작은쪽으로도 변환이 가능합니다. (8byte to 4byte)

그렇다면 아래와 같은 방식은 어떨까요?

 

private static void Main(string[] args)
{
	int intValue = 0;
	long longValue = 9223372036854775807; // = long.MaxValue
	intValue = (int)longValue;
	Console.WriteLine(intValue);

	// Result
	// -1
	
	
	longValue = intValue;
	Console.WriteLine(longValue);

	// Result
	// -1
}

int형의 최대범위를 초과하여 문제가 생기며, 데이터 손실이 되어버립니다. (일명 쓰레기값이 되어렸습니다.)

추가된 코드로 다시 되돌려보아도 이미 손실이 생겨 원래의 값을 잃어버렸습니다. 일반적으로 사용되었던 Cast방식을 사용한다면 이러한 문제가 생길 수 있습니다. 우리는 이러한 사실을 간과하고 놓칠 수 있겠죠.

 

그러면 애당초 형변환을 실패했다면 강제로 형변환 시키지 않도록 하는 방법은 없을까요?

이러한 문제점을 해결해주는 것으로 닷넷에서는 as와 is 사용을 권장하고 있습니다. 하지만 위와 같이 struct(구조체) 형식에서는 사용을 할 수 없습니다.

 

대신 class에서는 사용이 가능하며, 이는 반대로 클래스와 구조체에게 있어서 케스팅 방식을 따로 권장하고 있습니다.

private class Animal
{
	int age = 0;
}

private class Human : Animal
{
	// Human Values..
}

private class Dog : Animal
{
	// Dog Values..
}

private class Cat : Animal
{
	// Cat Values..
}

private static void Main(string[] args)
{
	Animal animal = new Animal();
	Human human = new Human();
	Dog dog = new Dog();
	Cat cat = new Cat();

	human = dog as human;       // error
	dog = dog as cat;           // error
	animal = human as animal;   // error

	animal = (Animal)human;     // Loss Human Values Data
}

작성간 에러를 바로 확인 할 수 있는 방법이기도 하며, 아래와 같이 장점이 있습니다.

 

1. 방어적인 형변환 기법이다.

2. 강제형 변환이 옳은지 try/catch를 사용할 필요가 없으며, 한 줄 코드로 간결해진다. (안정적이다. 런타임에 효율적이다.)

3. 형변환이 정상적으로 되었는지 확인이 가능하다. (데이터 손실이 일어나지 않게 할 수 있다.)

4. 성능적인 면에서 좋다.

 

아래는 닷넷에서 제공하는 예제입니다.

IEnumerable<int> numbers = new[] { 10, 20, 30 };
IList<int> indexable = numbers as IList<int>;
if (indexable != null)
{
    Console.WriteLine(indexable[0] + indexable[indexable.Count - 1]);  // output: 40
}

해당 데이터형이 먼저 List형식인지 확인이 가능하며 이상 없이 스크립트가 실행되었습니다. 이는 try/catch를 사용하지 않고 얻을 수 있는 최적화적인 방법 중에 하나입니다.

 

추가로 요약을 하자면, 강제형변환보다는 is 나 as를 먼저 사용하고, 해당되지 않는다면 일반적인 강제형변환을 사용하는 것이 좋다고 할 수 있습니다.

 

성능적인 면에서도 강제형변환보다는 좋습니다. 아래의 예제를 통해 알아봅시다.

if (myobject is Student)
{
    Student objStudent = (Student)myobject;
}

해당 오브젝트가 먼저 학생인지 확인하고, 학생이 맞다면 형변환을 시도합니다. 코드 작성간 이상은 없지만, 우리가 원하는 사용 이유는 아닙니다.

 

조금 더 간결하게 수정하자면, 아래와 같은 코드가 됩니다.

Student objStudent = (Student) myobject;

간결하지만, 이는 해당 오브젝트가 학생이 맞는지도 정확하지 않은 상황에서 예외상황을 초래할 수 있습니다.

 

다시 아래와 같이 수정합니다.

Student objStudent = myobject as Student;
if (objStudent != null)
{
    //use the object
}

as 키워드는 변환 중 이상이 있다면 null을 반환합니다. 이상이 없다면 바로 코드를 사용할 수 있는 상태가 됩니다. 처음에는 형변환을 위해 두 번의 과정이 있었지만, 지금은 형변환을 한 번에 수행하였습니다.

 

이와 같이 C# 스크립트 작성 중에는 강제형변환 보다는 as, is를 먼저 고려하는 쪽이 좋다고 할 수 있겠습니다.

 

참고: https://docs.microsoft.com/ko-kr/dotnet/csharp/language-reference/operators/type-testing-and-cast

참고: https://codewala.net/2011/03/11/is-vs-as-operators-performance-implications/

반응형

댓글