Recent Post

Recent Comment

Archive

2020. 8. 6. 00:22 C#
implicit explicit
Type Keyword Type Keyword

C#에서는 사용자 정의 형변환을 지원한다.

예를 들어 아래와 같은 클래스가 있다고 생각해보자.

public class Student

{

    public string Name { get; set; }

    public int Age { get; set; }

 

    public Student (string name) { Name = name; }

}

 

이 때 Student 클래스의 인스턴스 자체를 string 형식으로 암시적 혹은 명시적으로 변환하고 싶다면 사용자 정의 형변환을 통해 암시적/묵시적 형변환을 재정의할 수 있다.

 

public static implicit operator string (Student s)

{

    return s.Name;

}

위 코드는 implicit을 사용하여 Student 클래스의 string에 대한 암시적 형변환을 재정의한 코드이다.

따라서 아래와 같이 사용 가능하다.

 

var student1 = new Student("John");

string studentName = student1; // student1.Name이 반환됨

 

람다식을 사용하면 재정의 구문을 다음과 같이 간략하게 작성할 수 있다.

public static implicit operator string (Student s) => s.Name;

 

반대로 explicit을 사용하여 명시적 형변환을 재정의할 수도 있다.

 

public static explicit operator int (Student s) => s.Age;

명시적 형변환을 재정의한 코드이다.

 

var student1 = new Student("John");

student1.Age = 17;

 

int studentAge = (int)student1;

명시적 형변환은 위와 같이 사용한다.

 

주의할 점은 같은 형식에 대해 암시적/명시적 형변환을 모두 재정의할 수 없다는 것이다.

이를테면 아래와 같이 작성하는 것은 허용되지 않는다.

public static implicit operator string (Student s) => s.Name;

public static explicit operator string (Student s) => s.Name;

위 코드는 같은 형식(string)에 대해 암시적/명시적 형변환을 모두 재정의하고 있기 때문에 컴파일 에러가 발생한다.

 

추가적으로, 반드시 클래스 형식이 인자로 올 필요는 없다. 아래와 같은 방식도 허용된다.

public static explicit operator Student (string str) => new Student(str);

 

var name = "John";

var student1 = (Student)name; // 사용자 정의 형변환을 통해 name을 생성자에 넘겨 새로운 객체가 생성되어 반환된다.

 

 

또 한가지 주의할 점이 있는데 이런식으로 사용자 정의 형변환을 통해 생성된 '인스턴스'는 완전히 새로운 객체라는 점이다.

이해하기 쉽게 또 다른 예를 들어 설명해보겠다.

 

public class A

{

    int width;

    int height;

    public A (int width, int height)

    {

        this.width = width;

        this.height = height;

    }

    public static explicit operator B (A a) => new B(a.width * a.height);

}

 

public class B

{

    int area;

    public B (int area) { this.area = area; }

}

 

위와 같은 두 클래스 A, B가 있을 때, 명시적 형변환을 통해 A의 인스턴스를 B의 참조로 변환 및 대입하려고 한다면,

 

var a = new A(10,20);

var b = (B)a;

 

위 코드에서 원하는 것은 B형식으로 변환된 a였으나, 실제로는 새로운 B의 인스턴스이다.

무슨 뜻이냐면 정상적인 원래의 캐스팅 방식이라면 a와 b는 서로 같은 인스턴스를 참조해야 하는데, 이 둘은 서로 아예 다른 인스턴스를 참조하고 있다는 뜻이다.

 

Bitmap bitmap = Image.FromFile("myImage.bmp");

Image image = (Image)bitmap1;

image.Dispose();

 

위 식에서 image를 Dispose했지만, bitmap 역시 Dispose된다. 왜냐하면 bitmap와 image는 같은 인스턴스를 참조하고 있기 때문이다.

 

하지만 사용자 정의 형변환으로 재정의된 캐스팅에서 예시로 든 방식을 사용할 경우, 두 참조가 서로 다른 인스턴스를 참조하게 되기 때문에 예상치 못한 결과를 가져오거나, 메모리가 누수될 수 있다는 점을 주의하자.

'C#' 카테고리의 다른 글

Test  (0) 2022.05.10
Parallel.For()  (0) 2020.08.03
ArrayList  (0) 2020.08.03
posted by Dv Jm