== 연산자는 참조 방식, Equals() 메소드는 오버라이드를 해야 내용을 비교할 수 있다.

참조 타입에서 == 연산자는 참조 방식으로 오브젝트를 비교하지만, Equals 메소드는 오브젝트가 담고 있는 내용을 비교하기 위해 오버라이드 되어야 한다.

만약, 참조 타입에서 Equals 메소드가 오버라이드 되지 않으면, == 연산자처럼 참조 방식으로 오브젝트를 비교하게 된다.

아래는 같은 클래스로 동일한 객체를 생성했을 때, == 연산자와 Equals() 가 어떻게 두 객체를 비교하는지에 대한 예시 코드이다.

using System;

namespace Equal
{
	class CustomClass
	{
		int X;
		public CustomClass(int x)
		{
			X = x;
		}
	}



	internal class Program
	{
		static void Main(string[] args)
		{
			var customClass1 = new CustomClass(1);
			var customClass2 = new CustomClass(1);
			Console.WriteLine($"customClass1 == customClass2: " +
				$"{customClass1 == customClass2}"); // false
			Console.WriteLine($"customClass1.Equals(customClass2): " +
				$"{customClass1.Equals(customClass2)}"); // false
		}
	}
}

같은 클래스로 동일한 객체를 생성했음에도 두 객체가 다르다는 결과가 나왔다.

이유는 == 연산자와 Equals() 는 참조 비교를 하는데 두 객체가 각각 다른 주소를 갖고 있기 때문에 다르다고 판단하게 된다.

그렇다면, 클래스로 만들어진 오브젝트를 참조 비교가 아닌 내용 비교를 하게 하려면 어떻게 해야할까?

아래 코드와 같이 Equals() 메소드를 내용 비교를 할 수 있도록 오버라이드하면 된다.

(아래 예시 코드에서는 GetHashCode()를 사용하는데, 생략해도 됨. 해당 메소드는 기회가 되면 다루어보겠음.)

using System;

namespace Equal
{
	//class CustomClass
	//{
	//	int X;
	//	public CustomClass(int x)
	//	{
	//		X = x;
	//	}
	//}

	class CustomClassOverridingEquals
	{
		int X;
		public CustomClassOverridingEquals(int x)
		{
			X = x;
		}

		// Equals() 오버라이드
		public override bool Equals(object obj) 
		{
			var item = obj as CustomClassOverridingEquals;

			if (item == null)
			{
				return false;
			}

			return X == item.X;
		}

		// Equalis() 오버라이드 하기 위해 필요한 메소드
		public override int GetHashCode()
		{
			return X.GetHashCode();
		}
	}

	internal class Program
	{
		static void Main(string[] args)
		{
			//var customClass1 = new CustomClass(1);
			//var customClass2 = new CustomClass(1);
			//Console.WriteLine($"customClass1 == customClass2: " +
			//	$"{customClass1 == customClass2}"); // false
			//Console.WriteLine($"customClass1.Equals(customClass2): " +
			//	$"{customClass1.Equals(customClass2)}"); // false

			var customClass1 = new CustomClassOverridingEquals(1);
			var customClass2 = new CustomClassOverridingEquals(1);
			Console.WriteLine($"customClass1 == customClass2: " +
				$"{customClass1 == customClass2}"); // true
			Console.WriteLine($"customClass1.Equals(customClass2): " +
				$"{customClass1.Equals(customClass2)}"); // false
		}
	}
}

그렇다면, Value Type을 == 연산자로 비교하면 어떻게 될까?

Value Type인 struct로 객체를 만들어 == 연산자와 Equal() 로 비교해보겠다.

아래와 같이 struct를 == 연산자로 비교할 수 없음을 알 수 있다.

image-20220705201147573

하지만, Value Type에서 .Equals() 는 오버라이드 없이도 제대로 비교한다는 것을 알 수 있다.

using System;

namespace EqualValueType
{
	struct CustomStruct
	{
		int X;

		public CustomStruct(int x)
		{
			X = x;
		}
	}

	internal class Program
	{
		static void Main(string[] args)
		{
			var customStruct1 = new CustomStruct(1);
			var customStruct2 = new CustomStruct(1);
			//Console.WriteLine($"customStruct1 == customStruct2: " +
			//	$"{customStruct1 == customStruct2}"); // error
			Console.WriteLine($"customStruct1.Equals(customStruct2): " +
				$"{customStruct1.Equals(customStruct2)}"); // true
		}
	}
}

정리: 참조 타입과 값 타입에서 == 연산자와 Equals() 메소드 요약

아래와 같이 정리해보았다.

참조 타입에서 == 연산자와 Equals() 메소드는 둘다 참조 비교하지만, Equals() 메소드를 오버라이드하면 내용 비교를 할 수 있게 된다.

반면에 값 타입에서 참조 비교하는 == 연산자가 그 기능을 제공하지 못한다. 하지만, Eqauls() 메소드는 별도의 오버라이드 없이도 값 타입에서 내용 비교를 할 수 있게 된다.

image-20220705202424104

태그: ,

카테고리:

업데이트:

댓글남기기