且听疯吟 在此记录扯淡的青春
C# 中 String 类型比较

对象的比较

  • ==

    操作比较的是两个变量的值是否相等。对于引用型变量来说其值就是堆地址,因此表示的是是否指向了同一堆对象空间。

  • Equals

    操作表示的两个变量是否是对同一个对象的引用,即堆中的内容是否相同

  • 值类型是从 System.ValueType 派生的,该类型派生自 System.Object。但是 System.ValueType 重写了

Equals 方法,所以两个 ValueType 派生出的对象的字段值相等时,Equals 就返回 True
而对其他对象(引用类型),只有指针指向同一堆空间地址 Equals 才会返回 True

```csharp
class Program
{
    static void Main(string[] args) {
        var x = new P { I = 1 };
        var y = new P { I = 1 };
        var z = x;
        Console.WriteLine(x.Equals(y)); // False
        Console.WriteLine(x.Equals(z)); // True

        var a = new Q { I = 1 };
        var b = new Q { I = 1 };
        Console.WriteLine(a.Equals(b)); // True
    }
}

class P
{
    public int I { get; set; }
}

struct Q
{
    public int I { get; set; }
}
```

String 的特殊处理

StringEquals 的特殊处理(重写 Equals== 方法等等)使得 String 更类似于值类型
在一般用于都是 string 的比较时,Equals== 表现相同
如以下代码:

string a = new string(new char[] { 'h', 'e', 'l', 'l', 'o' });
string b = new string(new char[] { 'h', 'e', 'l', 'l', 'o' }); 
//a 和 b 通过 new 操作符开辟了两个内存空间,因此是不同的对象
Console.WriteLine(a == b); // True
Console.WriteLine(a.Equals(b)); // True
// 由于 String 重写了 Equals 和 == 方法,实际上比较的是 a 和 b 的内容而不是堆地址

object oa = a;
object ob = b;
Console.WriteLine(oa == ob); // False 
// 调用的是 Object 的 == 比较,因此是比较的 a 和 b 两个对象的堆地址,所以结果是 False
Console.WriteLine(oa.Equals(ob)); // True
// 由于多态性:Equals 是一个 Virtual 方法,其行为准则遵循基本语法,
// 由于父类的引用可以指向子类的对象,而运行期的方法调用都是和具体的对象确切类型绑定的,
// 因此调用 object 的 Equals 方法其实是调用子类 String 的 Equals 方法,
// 比较的是 a 和 b 的内容,所以结果是 True

a = "hello";
b = "hello"; // 注意和 new 并不相同

Console.WriteLine(a == b); // True
Console.WriteLine(a.Equals(b)); // True

oa = a;
ob = b;

Console.WriteLine(oa == ob); // True
Console.WriteLine(oa.Equals(ob)); // True
// 两个都相等是因为系统并没有给字符串 b 分配内存,
// 只是将 "hello" 指向了b, 所以 a 和 b 指向的是同一个字符串对象,
// 可以看做字符串在这种赋值的情况下做了内存的优化

string c = "hello";
object d = "hello";
Console.WriteLine(c.Equals(d)); // True
Console.WriteLine(d.Equals(c)); // True
Console.WriteLine(c == d); // True 
// 如上所说的原因,a 和 b 指向的同一字符串对象

string e = new string(new char[] { 'h', 'e', 'l', 'l', 'o' });
object f = new string(new char[] { 'h', 'e', 'l', 'l', 'o' });
Console.WriteLine(e == f); // False
Console.WriteLine(e.Equals(f)); // True
Console.WriteLine(f.Equals(e)); // True 
// 调用了 String 的 Equals

晕了没?

这些都不重要 :)
重要的是记住在比较对象时,尽量将两边转换为同一类型比较,避免掉进隐式转换的坑里

  • posted on 2014-02-21 17:18
  • C#