Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Nem kell egyéni logikát implementálnia a típusok referencia egyenlőségi összehasonlításának támogatásához. Ezt a funkciót a statikus Object.ReferenceEquals metódus minden típushoz biztosítja.
Az alábbi példa bemutatja, hogyan állapítható meg, hogy két változó rendelkezik-e egyenlőségihivatkozással, ami azt jelenti, hogy ugyanarra az objektumra hivatkoznak a memóriában.
A példa azt is bemutatja, hogy Object.ReferenceEquals miért ad vissza mindig false értéktípusokhoz. Ennek oka boxing, amely külön objektumpéldányokat hoz létre az egyes értéktípus-argumentumokhoz. Emellett nem szabad a ReferenceEquals-t használni a karakterláncok egyenlőségének meghatározásához.
Példa
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
*/
Az Equals megvalósítása az System.Object univerzális alaposztályban szintén elvégzi a referenciaegyenlőség-ellenőrzést, de a legjobb, ha ezt nem használja, mert ha egy osztály felülírja a metódust, előfordulhat, hogy az eredmények nem a vártak. Ugyanez igaz a == és != operátorokra is. Ha referenciatípusokon működnek, a == és a != alapértelmezett viselkedése a referencia-egyenlőség ellenőrzése. A származtatott osztályok azonban túlterhelhetik az operátort egy értékegyenlőség-ellenőrzés végrehajtásához. A hibalehetőség minimalizálása érdekében a legjobb, ha mindig ReferenceEquals használ, amikor meg kell határoznia, hogy két objektum rendelkezik-e hivatkozásegyenlőséggel.
Az ugyanazon az összeállításon belüli állandó stringeket a futtatókörnyezet mindig internálja. Ez azt jelenti, hogy az egyedi literál sztringből csak egy példányt tart fenn. A futtatókörnyezet azonban nem garantálja, hogy a futásidőben létrehozott sztringek internálva lesznek, és azt sem garantálja, hogy a különböző szerelvényekben lévő két azonos konstans sztring internálva van.
Jegyzet
ReferenceEquals az értéktípusok esetében false-et ad vissza a boxingmiatt, mivel minden argumentumot külön objektumba csomagolnak.