Humility

아무리 노력해도 최고가 되지 못할 수 있다⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀그럼에도 노력하는자가 가장 겸손한 것 아닌가

공부하는 블로그

유니티/문법

[Unity] 유니티 C#) Casting ( 형변환 )

새벽_글쓴이 2025. 1. 16. 21:15
반응형

형변환 이란?

하나의 데이터 타입을 다른 데이터 타입으로 변환하는 것


형변환의 종류

암시적 형변환 ( 자동 형변환 )

int num = 10;
float floatNum = num; // int → float 자동 변환
long longNum = num;   // int → long 자동 변환

 

사용 시기

  • 작은 크기의 데이터 타입에서 큰 크기로 변환할 때
  • 데이터 손실의 위험이 없어 자동으로 변환됨

명시적 형 변환 ( 강제 형변환 )

float floatNum = 10.5f;
int num = (int)floatNum; // float → int 강제 변환
// 10이 저장됨 (소수점 이하 손실)

 

사용시기

  • 큰 크기의 데이터 타입에서 작은 크기로 변환할 때
  • 데이터 손실의 가능성이 있어 명시적으로 변환해야 함

사용 예시

기본 데이터 타입 변환
public class PlayerController : MonoBehaviour
{
    private float speed = 5.5f;

    void Update()
    {
        // float을 int로 변환 (체력 계산 등에 사용)
        int roundedSpeed = (int)speed; // 5가 됨
        
        // int를 float으로 변환 (부드러운 움직임 계산 등에 사용)
        int score = 100;
        float smoothScore = score; // 자동 변환
    }
}

 

게임오브젝트와 컴포넌트 변환
public class Enemy : MonoBehaviour
{
    void OnTriggerEnter(Collider other)
    {
        // GameObject를 Player 타입으로 변환 시도
        Player player = other.gameObject.GetComponent<MonoBehaviour>() as Player;
        
        if(player != null)
        {
            player.TakeDamage(10);
        }
    }
}

주의사항

1. 데이터 손실 가능성

float health = 95.7f;
int roundedHealth = (int)health; // 95가 됨 (소수점 손실)

 

2. 변환 실패 가능성

public void HandleObject(GameObject obj)
{
    // 잘못된 방법 (예외 발생 가능)
    Player player = (Player)obj;
    
    // 안전한 방법
    Player safePlayer = obj as Player;
    if(safePlayer != null)
    {
        // 변환 성공
    }
}

 

3. 성능 고려

void Update()
{
    // 나쁜 예 - 매 프레임마다 형변환
    for(int i = 0; i < 1000; i++)
    {
        float value = (float)i;
        // 처리...
    }
    
    // 좋은 예 - 필요한 경우에만 형변환
    float convertedValue = (float)someInteger;
    for(int i = 0; i < 1000; i++)
    {
        // convertedValue 사용
    }
}

C# 형변환의 다양한 방법

1. typeof 연산자

타입의 정보를 얻는 연산자
Type t = typeof(string);
Debug.Log(t.Name); // "String" 출력

 

간단예제 및 주의사항

public class Weapon : MonoBehaviour { }
public class Sword : Weapon { }
public class Bow : Weapon { }

public class WeaponManager : MonoBehaviour 
{
    void CheckWeapon(Weapon weapon)
    {
        // 문제가 되는 상황
        if(weapon.GetType() == typeof(Weapon))
        {
            // Sword나 Bow는 여기서 false가 됨
            // 실제로는 무기지만 정확한 타입이 다르기 때문
        }

        // 더 나은 방법들
        // 1. IsSubclassOf 사용
        if(weapon.GetType().IsSubclassOf(typeof(Weapon)))
        {
            Debug.Log("이것은 무기의 파생 클래스입니다.");
        }

        // 2. is 연산자 사용
        if(weapon is Weapon)
        {
            Debug.Log("이것은 무기입니다. (파생 클래스도 포함)");
        }
    }
}

2.GetType() 메서드

객체의 실제 타입을 얻는 메서드
string str = "Hello";
Type type = str.GetType();
Debug.Log(type.Name); // "String" 출력

 

간단예제 및 주의사항

public class ItemSystem : MonoBehaviour
{
    void ProcessItem(Item item)
    {
        // 문제가 되는 상황
        Type itemType = item.GetType(); // item이 null이면 NullReferenceException 발생

        // 안전한 방법
        if(item != null)
        {
            Type itemType = item.GetType();
            Debug.Log($"아이템 타입: {itemType.Name}");
        }
        else
        {
            Debug.LogWarning("아이템이 null입니다!");
        }
    }
}

3. is와 as 연산자

is: 타입 검사
as: 안전한 타입 변환
object obj = "Hello";
if(obj is string) // 타입 검사
{
    string str = obj as string; // 안전한 변환
}

 

is 간단예제 및 주의사항

public class Enemy : MonoBehaviour { }
public class Boss : Enemy { }
public class MinionBoss : Boss { }

public class EnemyManager : MonoBehaviour
{
    void HandleEnemy(GameObject obj)
    {
        var component = obj.GetComponent<MonoBehaviour>();

        // is의 특징: 상속 관계의 모든 객체를 확인
        if(component is Enemy)  // Enemy, Boss, MinionBoss 모두 true
        {
            Debug.Log("적입니다!");
        }

        // 패턴 매칭을 사용한 더 유용한 방법
        if(component is Boss boss)
        {
            // boss 변수를 바로 사용 가능
            boss.TriggerBossPhase();
        }
    }
}

 

as 간단예제 및 주의사항

public class InteractionSystem : MonoBehaviour
{
    void HandleInteraction(MonoBehaviour component)
    {
        // 값 형식에는 사용 불가
        // int number = obj as int; // 컴파일 에러!

        // 참조 형식에만 사용 가능
        var enemy = component as Enemy;

        // as 연산자의 장점: 형변환 실패시 예외 대신 null 반환
        if(enemy != null)
        {
            enemy.Attack();
        }
        else
        {
            Debug.Log("Enemy가 아닙니다.");
        }

        // 캐스팅과의 비교
        try
        {
            Enemy forcedEnemy = (Enemy)component; // 실패시 예외 발생
        }
        catch(InvalidCastException)
        {
            Debug.LogError("형변환 실패!");
        }
    }
}

4. 직접 캐스팅 ( Type Casting )

명시적 형변환 연산자
double d = 3.14;
int i = (int)d; // 명시적 형변환

 

간단예제 및 주의사항

public class DamageSystem : MonoBehaviour
{
    void CalculateDamage()
    {
        // 1. 데이터 손실
        float damage = 15.7f;
        int roundedDamage = (int)damage; // 15가 됨 (0.7 손실)

        // 2. OverflowException 가능성
        long bigNumber = long.MaxValue;
        int smallNumber = (int)bigNumber; // OverflowException 발생

        // 3. InvalidCastException 가능성
        GameObject obj = new GameObject();
        try
        {
            Enemy enemy = (Enemy)obj.GetComponent<MonoBehaviour>();
            // MonoBehaviour가 Enemy가 아니면 예외 발생
        }
        catch(InvalidCastException)
        {
            Debug.LogError("Enemy로 변환 실패!");
        }
    }
}

5. Convert 클래스

다양한 타입 변환 메서드 제공
string numberString = "123";
int number = Convert.ToInt32(numberString);

 

간단예제 및 주의사항

public class DataConverter : MonoBehaviour
{
    void ConvertData(string input)
    {
        try
        {
            // FormatException: 잘못된 형식
            int number = Convert.ToInt32("abc"); // 실패

            // OverflowException: 값 범위 초과
            int tooLarge = Convert.ToInt32("999999999999"); // 실패

            // ArgumentNullException: null 입력
            float value = Convert.ToSingle(null); // 실패
        }
        catch(FormatException)
        {
            Debug.LogError("잘못된 형식입니다.");
        }
        catch(OverflowException)
        {
            Debug.LogError("값이 범위를 벗어났습니다.");
        }
        catch(ArgumentNullException)
        {
            Debug.LogError("null은 변환할 수 없습니다.");
        }
    }
}

6. Parse 메서드

문자열을 다른 타입으로 변환
string numStr = "456";
int num = int.Parse(numStr);

7.TryParse 메서드

안전한 형식 변환 시도
string input = "789";
if(int.TryParse(input, out int result))
{
    Debug.Log("변환 성공: " + result);
}

 

간단예제 및 주의사항 ( ParseTryparse의 차이 )

public class ScoreSystem : MonoBehaviour
{
    void ProcessScore(string scoreText)
    {
        // Parse: 실패시 예외 발생
        try
        {
            int score = int.Parse(scoreText);
            UpdateScore(score);
        }
        catch(FormatException)
        {
            Debug.LogError("점수 형식이 잘못되었습니다.");
        }

        // TryParse: 안전한 방식
        if(int.TryParse(scoreText, out int parsedScore))
        {
            UpdateScore(parsedScore);
        }
        else
        {
            Debug.LogWarning("점수를 변환할 수 없습니다.");
        }
    }

    private void UpdateScore(int score)
    {
        // 점수 업데이트 로직
    }
}
반응형