Share via


방법: 참조 일치(같음) 테스트(C# 프로그래밍 가이드)

형식의 참조 일치 비교를 지원하기 위해 사용자 지정 논리를 구현할 필요는 없습니다. 이 비교 기능은 정적 메서드인 ObjectReferenceEquals()에서 모든 형식에 대해 제공합니다.

다음 예제에서는 두 변수가 참조 일치 관계에 있는지, 즉 두 변수가 메모리에 있는 동일한 개체를 참조하는지 여부를 확인하는 방법을 보여 줍니다.

또한 이 예제에서는 ObjectReferenceEquals()가 값 형식에 대해 항상 false를 반환하는 이유 및 문자열 일치를 확인하는 데 ReferenceEquals()를 사용하면 안 되는 이유를 보여 줍니다.

예제

    namespace TestReferenceEquality
    {
        struct TestStruct
        {
            public int Num { get; private set; }
            public string Name { get; private set; }

            public TestStruct(int i, string s) : this()
            {
                Num = i;
                Name = s;
            }
        }

        class TestClass
        {
            public int Num { get; set; }
            public string Name { get; set; }
        }

        class Program
        {
            static void Main()
            {
                // Demonstrate reference equality with reference types.
                #region ReferenceTypes

                // Create two reference type instances that have identical values.
                TestClass tcA = new TestClass() { Num = 1, Name = "New TestClass" };
                TestClass tcB = new TestClass() { Num = 1, Name = "New TestClass" };

                Console.WriteLine("ReferenceEquals(tcA, tcB) = {0}",
                                    Object.ReferenceEquals(tcA, tcB)); // false

                // After assignment, tcB and tcA refer to the same object. 
                // They now have reference equality. 
                tcB = tcA;
                Console.WriteLine("After asignment: ReferenceEquals(tcA, tcB) = {0}",
                                    Object.ReferenceEquals(tcA, tcB)); // true

                // Changes made to tcA are reflected in tcB. Therefore, objects
                // that have reference equality also have value equality.
                tcA.Num = 42;
                tcA.Name = "TestClass 42";
                Console.WriteLine("tcB.Name = {0} tcB.Num: {1}", tcB.Name, tcB.Num);
                #endregion

                // Demonstrate that two value type instances never have reference equality.
                #region ValueTypes

                TestStruct tsC = new TestStruct( 1, "TestStruct 1");

                // Value types are copied on assignment. tsD and tsC have 
                // the same values but are not the same object.
                TestStruct tsD = tsC;
                Console.WriteLine("After asignment: ReferenceEquals(tsC, tsD) = {0}",
                                    Object.ReferenceEquals(tsC, tsD)); // false
                #endregion

                #region stringRefEquality
                // Constant strings within the same assembly are always interned by the runtime.
                // This means they are stored in the same location in memory. Therefore, 
                // the two strings have reference equality although no assignment takes place.
                string strA = "Hello world!";
                string strB = "Hello world!";
                Console.WriteLine("ReferenceEquals(strA, strB) = {0}",
                                 Object.ReferenceEquals(strA, strB)); // true

                // After a new string is assigned to strA, strA and strB
                // are no longer interned and no longer have reference equality.
                strA = "Goodbye world!";
                Console.WriteLine("strA = \"{0}\" strB = \"{1}\"", strA, strB);

                Console.WriteLine("After strA changes, ReferenceEquals(strA, strB) = {0}",
                                Object.ReferenceEquals(strA, strB)); // false

                // A string that is created at runtime cannot be interned.
                StringBuilder sb = new StringBuilder("Hello world!");
                string stringC = sb.ToString(); 
                // False:
                Console.WriteLine("ReferenceEquals(stringC, strB) = {0}",
                                Object.ReferenceEquals(stringC, strB));

                // The string class overloads the == operator to perform an equality comparison.
                Console.WriteLine("stringC == strB = {0}", stringC == strB); // true

                #endregion

                // Keep the console open in debug mode.
                Console.WriteLine("Press any key to exit.");
                Console.ReadKey();
            }
        }
    }

    /* Output:
        ReferenceEquals(tcA, tcB) = False
        After asignment: ReferenceEquals(tcA, tcB) = True
        tcB.Name = TestClass 42 tcB.Num: 42
        After asignment: ReferenceEquals(tsC, tsD) = False
        ReferenceEquals(strA, strB) = True
        strA = "Goodbye world!" strB = "Hello world!"
        After strA changes, ReferenceEquals(strA, strB) = False
    */

공통적인 기본 클래스인 System.Object의 Equals 구현에서도 참조 일치 검사를 수행하지만 클래스에서 이 메서드를 재정의할 경우 예기치 않은 결과가 발생할 수도 있으므로 이 메서드는 사용하지 않는 것이 가장 좋은 방법입니다. 같은 기준이 == 및 != 연산자에도 적용됩니다. == 및 != 연산자가 참조 형식에 대해 작동할 경우 기본적으로 참조 일치 검사를 수행하게 됩니다. 그러나 파생 클래스에서 이러한 연산자를 오버로드하여 값 일치 검사를 수행할 수 있습니다. 오류 발생 가능성을 최소화하려면 두 개체가 참조 일치 관계에 있는지 여부를 확인해야 하는 경우에 항상 ReferenceEquals()를 사용하는 것이 가장 좋은 방법입니다.

동일한 어셈블리 내의 상수 문자열은 항상 런타임에 내부 풀에 추가됩니다. 즉, 각각의 고유한 리터럴 문자열에 대해 인스턴스가 하나만 유지 관리됩니다. 하지만 런타임에서는 런타임에 만들어진 문자열이 내부 풀에 추가되는 것을 보장하거나 서로 다른 어셈블리에 있는 동일한 두 상수 문자열이 내부 풀에 추가되는 것을 보장하지 않습니다.

참고 항목

기타 리소스

같음 비교(C# 프로그래밍 가이드)