Testen op referentie gelijkheid (identiteit) (C#-programmeerhandleiding)
U hoeft geen aangepaste logica te implementeren ter ondersteuning van referentie-gelijkheidsvergelijkingen in uw types. Deze functionaliteit wordt geleverd voor alle typen door de statische Object.ReferenceEquals methode.
In het volgende voorbeeld ziet u hoe u kunt bepalen of twee variabelen verwijzen naar gelijkheid, wat betekent dat ze verwijzen naar hetzelfde object in het geheugen.
In het voorbeeld ziet u ook waarom Object.ReferenceEquals altijd false
retourneert voor waardetypen. Dit komt door boksen, waardoor afzonderlijke objectexemplaren worden gemaakt voor elk waardetypeargument. Daarnaast moet u ReferenceEquals niet gebruiken om de gelijkheid van tekenreeksen te bepalen.
Voorbeeld
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) = {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 assignment: 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 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) = {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 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
*/
De implementatie van Equals
in de universele basisklasse System.Object voert ook een referentie gelijkheidscontrole uit, maar dit is het beste niet te gebruiken omdat, als een klasse de methode overschrijft, de resultaten mogelijk niet zijn wat u verwacht. Hetzelfde geldt voor de operators ==
en !=
. Wanneer ze werken op referentietypen, is het standaardgedrag van ==
en !=
het uitvoeren van een referentie gelijkheidscontrole. Afgeleide klassen kunnen de operator echter overbelasten om een waarde gelijkheidscontrole uit te voeren. Om de kans op fouten te minimaliseren, kunt u het beste altijd ReferenceEquals gebruiken wanneer u moet bepalen of twee objecten referentie-gelijkheid hebben.
Constante tekenreeksen die zich binnen eenzelfde assembly bevinden, worden altijd door de runtime geïnterneerd. Dat wil gezegd, er wordt slechts één exemplaar van elke unieke letterlijke tekenreeks bijgehouden. De runtime garandeert echter niet dat tekenreeksen die tijdens de runtime zijn gemaakt, worden geïnterneerd, en ook niet dat twee gelijke constante tekenreeksen in verschillende assembly's worden geïnterneerd.
Notitie
ReferenceEquals
retourneert false
voor waardetypen als gevolg van boksen, omdat elk argument onafhankelijk in een afzonderlijk object wordt geplaatst.