Aracılığıyla paylaş


Referans eşitliğini (Kimlik) test etme (C# Programlama Kılavuzu)

Türlerinizde başvuru eşitliği karşılaştırmalarını desteklemek için herhangi bir özel mantık uygulamanız gerekmez. Bu işlevsellik, statik Object.ReferenceEquals yöntemi tarafından tüm türler için sağlanır.

Aşağıdaki örnek, iki değişkenin başvuru eşitliğine sahip olup olmadığının nasıl belirleneceğini gösterir ve bu da bellekteki aynı nesneye başvuracakları anlamına gelir.

Örnekte, Object.ReferenceEquals neden her zaman değer türleri için false döndürdüğü de gösterilmektedir. Bunun nedeni, her değer türü bağımsız değişkeni için ayrı nesne örnekleri oluşturan kutulamasıdır. Ayrıca, dize eşitliğini belirlemek için ReferenceEquals kullanmamalısınız.

Örnek

using System.Text;

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) = {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 assignment: ReferenceEquals(tcA, tcB) = {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 = {tcB.Name} tcB.Num: {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 boxed into separate objects when passed to ReferenceEquals.
            // Even if the same variable is used twice, boxing ensures they are different instances.
            TestStruct tsD = tsC;
            Console.WriteLine($"After assignment: ReferenceEquals(tsC, tsD) = {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) = {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 = '{strA}' strB = '{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) = {Object.ReferenceEquals(stringC, strB)}");

            // The string class overloads the == operator to perform an equality comparison.
            Console.WriteLine($"stringC == strB = {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 assignment: ReferenceEquals(tcA, tcB) = True
    tcB.Name = TestClass 42 tcB.Num: 42
    After assignment: ReferenceEquals(tsC, tsD) = False
    ReferenceEquals(strA, strB) = True
    strA = "Goodbye world!" strB = "Hello world!"
    After strA changes, ReferenceEquals(strA, strB) = False
    ReferenceEquals(stringC, strB) = False
    stringC == strB = True
*/

Equals evrensel temel sınıfındaki System.Object uygulaması da başvuru eşitliği denetimi gerçekleştirir, ancak en iyisi bunu kullanmamaktır çünkü bir sınıf yöntemi geçersiz kılarsa, sonuçlar beklediğiniz gibi olmayabilir. Aynı durum == ve != işleçleri için de geçerlidir. Başvuru türleri üzerinde çalışırken, == ve != varsayılan davranışı bir başvuru eşitliği denetimi gerçekleştirmektir. Ancak, türetilmiş sınıflar bir değer eşitliği denetimi gerçekleştirmek için işleci aşırı yükleyebilir. Hata olasılığını en aza indirmek için, iki nesnenin başvuru eşitliğine sahip olup olmadığını belirlemeniz gerektiğinde her zaman ReferenceEquals kullanmak en iyisidir.

Aynı derleme içindeki sabit dizeler her zaman çalışma zamanı sırasında içselleştirilir. Diğer bir ifadeyle, her benzersiz değişmez dizenin yalnızca bir örneği saklanır. Ancak çalışma zamanı, çalışma zamanında oluşturulan dizelerin bellekte ortak kullanıldığını garanti etmez ve farklı derlemelerdeki iki eşit sabit dizenin bellekte ortak kullanıldığını da garanti etmez.

Not

ReferenceEquals, her argümanın ayrı bir nesneye bağımsız olarak kutulandığı için, falsenedeniyle değer türleri için döndürür.

Ayrıca bkz.