본문 바로가기
IT/C#(CS)

CS 기초강좌 7. 값 타입과 참조 타입의 비교 연산자 == or Equality

by 신림83 2020. 11. 13.
반응형

CS 기초강좌 7. 값 타입과 참조 타입의 비교 연산자 == or Equality

먼저 참조타입의 비교에 대해서 보자.

먼저 객체를 비교 하는 방법에는 2가지가 있습니다.

연산자 ==, 그리고 System.Object가 제공하는 Equality 메소드입니다.

 

다음 코드를 보아요.

class classPoint 
{
    public int x = 0;
    public int y = 0;
}

class Program
{
    static void Main(string[] args)
    {
        classPoint cp1 = new classPoint();
        classPoint cp2 = cp1;
        classPoint cp3 = new classPoint();
    }
}

 cp1, cp2, cp3 세 가지의 변수가 있습니다. cp1, cp3은 각각 Heap영역에 존재합니다. cp2는 cp1이 바라보는 객체를 같이 바라보고 있습니다. 모든 변수가 바라보는 클래스의 x,y 값은 동일합니다.

 

비교 코드를 봅시다.

Console.WriteLine(cp1 == cp2);
Console.WriteLine(cp1 == cp3);

Console.WriteLine(cp1.Equals(cp2));
Console.WriteLine(cp1.Equals(cp3));

출력결과

참조값의 비교에서는 변수가 포인팅 하는 객체가 같아야지만, true가 나옵니다. 내부의 필드 값을 비교하지 않습니다. 실제 내부의 필드값을 비교하는 기능을 원하신다면 메소드를 따로 제공하시거나, 해당 기능들을 재정의 하면 됩니다.

 

연산자 재정의를 통하여 == 연산자를 재정의 해보겠습니다.

class classPoint 
{
    public int x = 0;
    public int y = 0;

    public static bool operator ==(classPoint cp1, classPoint cp2)
    {
        return cp1.x == cp2.x && cp1.y == cp2.y;
    }

    public static bool operator !=(classPoint cp1, classPoint cp2)
    {
        return cp1.x != cp2.x || cp1.y != cp2.y;
    }
}

연산자 == 재정의를 하면 반드시 연산자 != 또한 재정의 해주어야 합니다. 컴파일러가 그래라고 합니다.

 

결과를 볼까요?

Console.WriteLine(cp1 == cp2);
Console.WriteLine(cp1 == cp3);

출력결과

cp1 == cp3이 내부 필드 비교를 통하여 true를 반환합니다.

 

연산자 == 재정의를 통한 비교 기능 구현은 올 바를까?

 

아래 코드를 보겠습니다. 위의 연산자 재정의 코드는 그대로 존재합니다.

object cp1 = new classPoint();
object cp2 = cp1;
object cp3 = new classPoint();

Console.WriteLine(cp1 == cp2);
Console.WriteLine(cp1 == cp3);

출력결과

C#에서 모든 객체는 object를 상속합니다. 우리가 만든 클래스 또한 object로 받을 수가 있죠. 실제로도 많이 사용합니다. 이 오브젝트로 연산자 비교를 수행하면, object가 가지고 있는 연산자==의 기능을 수행합니다. classPoint에 재정의 해둔 기능이 수행되지 않습니다.

 

 이러한 문제를 피해 가려면 virtual 메소드 계념이 있어야 겠죠. 그래서 위와 같은 수정방법 보다는 Equality 메소드 재정의를 권장합니다.

 

Equality 

Equality 재정의를 통해 비교 연산을 수정해보겠습니다. 다음 코드를 보아요

class classPoint 
{
    public int x = 0;
    public int y = 0;

    public override bool Equals(object obj)
    {
        classPoint cp = obj as classPoint;
        return x == cp.x && y == cp.y;
    }
}

Equality 메소드는 System.Object가 virtual로 가지고 있습니다. 객체면 무조건 다 존재합니다. 이를 재정의 하였습니다. 연산자 ==의 통해서 실패했던 코드를 돌려보도록 합시다.

 

object cp1 = new classPoint();
object cp2 = cp1;
object cp3 = new classPoint();

Console.WriteLine(cp1.Equals(cp2));
Console.WriteLine(cp1.Equals(cp3));

출력결과

virtual 계념으로 작동하여 object를 비교하여도, 재정의한 equals 사용합니다. 

 

참조 타입의 비교 재정의를 원하시면 

연산자 ==, != 재정의는 원래의 목정에 맞게 두시고(참조의 비교)

Equals 메소드 재정의를 추천드립니다.

 

값타입의 비교

다음 코드를 봅시다.

public struct structPoint
{
    public int x;
    public int y;
}

class Program
{
    static void Main(string[] args)
    {
        structPoint sp1 = new structPoint();
        structPoint sp2 = sp1;
        structPoint sp3 = new structPoint();

        Console.WriteLine(sp1 == sp2);
        Console.WriteLine(sp1 == sp3);

        Console.WriteLine(sp1.Equals(sp2));
        Console.WriteLine(sp1.Equals(sp3));
    }
}

값타입은 기본적으로 연산자== 기능을 제공하지 않습니다.

연산자 == 제공하지 않음

하지만 연산자 재정의를 통해 구현할 수는 있습니다.

 

equals의 결과를 보자.

Console.WriteLine(sp1.Equals(sp2));
Console.WriteLine(sp1.Equals(sp3));

출력결과

값 타입에서 Equals 의 비교는 해당 객체의 메모리 영역을 비교하는 것입니다. 실제 객체의 내용을 비교합니다. 이 역시 재정의를 통해 원하는 바로 구현 가능합니다.

 

값 타입의 설명은 좀 간단한 편이네요..

 

찬찬히 보시면 이쁩니다.... ㅎㅎㅎ

봐주셔서 감사합니다.

반응형

댓글