JetBrains Rider 2025.2 Help

代码检查:可能的无意引用比较

C# 编译器在您对继承自彼此的类型对象使用相等运算符(==!= )且仅有一个类型重写了这些运算符的情况下,会发出“可能的无意引用比较”警告(CS0252/CS0253)。

相等运算符在其中一个类型中被重写这一事实意味着,当比较此类型的对象时,预期的是 值相等。 将这些对象与未重写相等运算符的类型对象进行比较时,将使用来自 System.Object 的重载,这会检查 引用相等。 因此发出警告是因为在这种情况下比较对象引用很可能是错误的。

尽管 JetBrains Rider 知道这些警告并为其提供 设计时通知 ,但它更进一步,检测到可能的无意引用比较的另一种情况——当仅有一个被比较的类型重写了 Equals()。 如果第二个对象的类型未重写 Equals() ,则比较将回退到 Equals()System.Object 中的实现,该实现执行引用标识检查,这对于值类型来说很可能不是预期的。

以下是一个代码清单,展示了这两种情况:

class MyType { } class TypeWithEquals : MyType { public override bool Equals(object obj) { throw new NotImplementedException(); } } class TypeWithEqOperators : MyType { public static bool operator ==(TypeWithEqOperators left, TypeWithEqOperators right) { throw new NotImplementedException(); } public static bool operator !=(TypeWithEqOperators left, TypeWithEqOperators right) { throw new NotImplementedException(); } } class Test { public Test(TypeWithEquals withEquals, TypeWithEqOperators withEqOperators, MyType parentObject) { bool a = withEqOperators == parentObject; // CS0253 bool b = withEquals == parentObject; // No compiler warnings, but JetBrains Rider issues its own warning here } }

此检查的另一种情况是使用相等运算符(==!= )比较接口类型。 由于这些运算符是静态的,即使在接口实现中将相等运算符重写为值比较,编译器也会默认使用 System.Object.ReferenceEquals()——即引用比较。

JetBrains Rider 会查找重写了相等运算符和/或 Equals() 的接口实现,如果检测到这样的实现,它会发出警告:

interface ISomeInterface{ } class SomeImplementation : ISomeInterface { public override bool Equals(object obj) => throw new NotImplementedException(); public override int GetHashCode() => throw new NotImplementedException(); } void ATest(ISomeInterface x, ISomeInterface y) { bool a = x == y; //Possible unintended reference comparison }

请注意,此检查会在整个解决方案(包括引用的库)中查找接口实现,其位置并不总是显而易见的。 在下面的示例中,即使您的任何 ICollection<object> 实现都未重写 Equals() 或相等运算符,JetBrains Rider 仍会检测到 mscorlib 中重写了 Equals()ICollection<object> 实现并发出警告。

void SomeTest(ICollection<object> x, ICollection<object> y) { bool a = x == y; //Possible unintended reference comparison }

尽管这种情况可能看起来有些防御性,但如果您使用非静态方法来比较接口,代码可能会更直接且更安全。 也就是说,如果您打算检查引用相等,可以使用 ReferenceEquals() ;如果您希望它在实现中被重写,可以使用 Equals() ;或者使用任何特定方法,例如 Enumerable.SequenceEqual() ,检查集合是否以相同顺序包含相等的对象。

最后修改日期: 2025年 9月 26日