您不必实现任何自定义逻辑来支持类型中的引用相等比较。 静态 Object.ReferenceEquals 方法为所有类型提供此功能。
下面的示例演示如何确定两个变量是否 引用相等性,这意味着它们引用内存中的同一对象。
该示例还显示了为什么 Object.ReferenceEquals 始终返回值类型的 false
。 这是由于装箱造成的,此操作会为每个值类型参数创建单独的对象实例。 此外,不应使用 ReferenceEquals 来确定字符串相等性。
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()
{
#region ReferenceTypes
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)}");
tcB = tcA;
Console.WriteLine($"After assignment: ReferenceEquals(tcA, tcB) = {Object.ReferenceEquals(tcA, tcB)}");
tcA.Num = 42;
tcA.Name = "TestClass 42";
Console.WriteLine($"tcB.Name = {tcB.Name} tcB.Num: {tcB.Num}");
#endregion
#region ValueTypes
TestStruct tsC = new TestStruct( 1, "TestStruct 1");
TestStruct tsD = tsC;
Console.WriteLine($"After assignment: ReferenceEquals(tsC, tsD) = {Object.ReferenceEquals(tsC, tsD)}");
#endregion
#region stringRefEquality
string strA = "Hello world!";
string strB = "Hello world!";
Console.WriteLine($"ReferenceEquals(strA, strB) = {Object.ReferenceEquals(strA, strB)}");
strA = "Goodbye world!";
Console.WriteLine($"strA = '{strA}' strB = '{strB}'");
Console.WriteLine("After strA changes, ReferenceEquals(strA, strB) = {0}",
Object.ReferenceEquals(strA, strB));
StringBuilder sb = new StringBuilder("Hello world!");
string stringC = sb.ToString();
Console.WriteLine($"ReferenceEquals(stringC, strB) = {Object.ReferenceEquals(stringC, strB)}");
Console.WriteLine($"stringC == strB = {stringC == strB}");
#endregion
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
}
Equals
通用基类中 System.Object 的实现也执行引用相等性检查,但最好不要使用此检查,因为,如果类碰巧重写该方法,结果可能不是预期的结果。 ==
和 !=
运算符也是如此。 在引用类型上运行时,==
和 !=
的默认行为是执行引用相等性检查。 但是,派生类可以重载运算符来执行值相等性检查。 为了最大程度地减少出错的可能性,最好在必须确定两个对象是否具有引用相等性时始终使用 ReferenceEquals。
运行时始终暂存同一程序集内的常量字符串。 也就是说,只维护每个唯一文本字符串的一个实例。 但是,运行时不能保证会暂存在运行时创建的字符串,也不保证会暂存不同程序集中两个相等的常量字符串。
备注
ReferenceEquals
因装箱的原因会返回值类型的 false
,因为每个参数都会独立装入一个单独的对象中。