프로그래밍/C#

[C#] casting

갓똥 2020. 2. 7. 17:43
728x90
반응형

1. casting

using System;

class Program {
    static void Main() {
        int    n = 3;
        double d = 3.4;
        
        d = n; // int => double - 데이터 손실 없음
        n = d; // double => int - 데이터 손실 방생 error
        n = (int)d;
    }
}

 ① 캐스팅 규칙

    => 데이터 손실이 발생하지 않은 경우 암시적 형 변환 될 수 있다.

    => 데이터 손실이 발생하는 경우 명시적 캐스팅을 해야 한다.

 


2. is, as

using System;

class Animal { }
class Dog : Animal {
    public void Cry() { Console.WriteLine("Dog Cry"); }
}

class Program {
    public static void foo(Animal a) {
        a.Cry();
    }
    
    static void Main() {
        foo(new Dog());
    }
}

 

함수 foo가 Animal을 인자로 받고 있으며, Animal의 모든 파생 클래스 또한 인자가 될 수 있다.
Main에서 Dog를 만들어서 보냈다.
분명 Dog안에는 Cry함수가 있지만, 하지만 Animal에는 Cry가 없으므로 호출할 수 없다. (에러)
이럴 경우 Aniaml 타입을 Dog 타입으로 다운캐스팅해서 사용할 수 있다.
using System;

class Animal { }
class Dog : Animal {
    public void Cry() { Console.WriteLine("Dog Cry"); }
}

class Program {
    public static void foo(Animal a) {
        // a.Cry();
        
        // Animal 참조 타입을 Dog 참조 타입으로 캐스팅
        Dog d = (Dog)a;
        d.Cry();
    }
    
    static void Main() {
        // foo(new Dog());
        foo(new Animal());
    }
}

 

근데 문제는, foo는 사실 Dog를 받는게 아닌 Animal을 받고 있다.
그래서 foo(new Animal()); 을 Main에서 실행한다면 캐스팅이 잘 못되어 예외가 발생한다. 
따라서 무조건 사용할 수 없고 타입을 조사한 후 사용해야 한다. 
using System;

class Animal { }
class Dog : Animal {
    public void Cry() { Console.WriteLine("Dog Cry"); }
}

class Program {
    public static void foo(Animal a) {
        // a.Cry();
        // Animal 참조 타입을 Dog 참조 타입으로 캐스팅
        // Dog d = (Dog)a;
        // d.Cry();
        
        if (a is Dog) {
            Dog d = (Dog)a;
            d.Cry();
        }
    }
    
    static void Main() {
        foo(new Dog());
        foo(new Animal());
    }
}

 ① is 연산자

    => 참조 변수가 가리키는 실제 타입을 조사 할 때 사용

 

using System;

class Animal { }
class Dog : Animal {
    public void Cry() { Console.WriteLine("Dog Cry"); }
}

class Program {
    public static void foo(Animal a) {
        // a.Cry();
        // Animal 참조 타입을 Dog 참조 타입으로 캐스팅
        
        // Dog d = (Dog)a; // 실패시 예외
        Dog d = a as Dog;  // 실패시 null 반환
        
        if(d!=null) {
            d.Cry();
        }
    }
    
    static void Main() {
        foo(new Dog());
        foo(new Animal());
    }
}

 ② 2가지 캐스팅 방법

using System;

class Program {
    static void Main() {
        int n = 3;
        object obj = n;
        
        // int n1 = obj as int; // error (값 타입에 null을 넣을 수 없다.)
        
        int? n1 = obj as int?; // ok
    }
}

 


3. 변환 연산자

using System;

class Point {
    private int x;
    private int y;
    public Point(int xPos, int yPos) {
        x = xPos;
        y = yPos;
    }
    public override string ToString() {
        return string.Format($"{x}, {y}");
    }
}

class Program {
    static void Main() {
        double d = 3.4;
        // int n1 = d;   // error
        int n1 = (int)d; // ok
        
        Point pt = new Point(1, 2);
        int n2 = pt;
    }
}

 

17~19라인의 코드는 위의 내용대로 명시적 캐스팅을 한 경우이다.
21~22라인의 코드는 pt 객체를 int에 넣어본 것이다.
하지만 컴파일러는 당연히 사용자 정의 타입을 int에 어떻게 넣는지 몰라 에러가 난다.
하지만 이걸 가능하게 할 수 있다.

 ① Point => int

    => public static explicit operator int(Point pt)

 

using System;

class Point {
    private int x;
    private int y;
    public Point(int xPos, int yPos) {
        x = xPos;
        y = yPos;
    }
    public override string ToString() {
        return string.Format($"{x}, {y}");
    }
    
    public static explicit operator int(Point pt) {
        return pt.x;
    }
}

class Program {
    static void Main() {
        double d = 3.4;
        // int n1 = d;   // error
        int n1 = (int)d; // ok
        
        Point pt = new Point(1, 2);
        // int n2 = pt; 
        int n2 = (int)pt; // 명시적 형변환 필수
    }
}

 

위의 내용은 명시적으로 꼭 타입을 적어주어야 한다.
using System;

class Point {
    private int x;
    private int y;
    public Point(int xPos, int yPos) {
        x = xPos;
        y = yPos;
    }
    public override string ToString() {
        return string.Format($"{x}, {y}");
    }
    
    public static explicit operator Point(int n) {
        return new Point(n, n);
    }
}

class Program {
    static void Main() {
        int n = 1;
        
        Point pt = (Point)n;
        Console.WriteLine(pt);
        
        // Point pt2 = n2 as Point; // error
    }
}

 ② int => Point

    => public static explicit operator Point(int pt)

 

 ③ as 연산자 사용시 변환연산자가 호출되지 않는다.

728x90
반응형