String.Equals和String.Compare与“==”的区别。需要解释。

15

以下是来自控制台应用程序的代码片段 -

class MyClass
{        
   public int GetDay(string data22)
    {
        int returnValue = 0;

        if (string.Compare(data22,"THURSDAY") == 0) // true
        {
            returnValue = (int)DayOfWeek.Thursday;
        }

        if (data22 == "THURSDAY") //false
        {
            returnValue = (int)DayOfWeek.Thursday;
        }

        if (string.Equals(data22, "THURSDAY"))//false
        {
            returnValue = (int)DayOfWeek.Thursday;
        }
        return returnValue;
    }
}

class Program
{
    static void Main(string[] args)
    {
        string ExecutionDay = "‎THURSDAY";
        MyClass obj1 = new MyClass();
        int MyDays = obj1.GetDay(ExecutionDay);
    }
}

问题是 - 为什么第一个比较方法(string.compare)能够运行,而其他两个比较方法在这种情况下不能运行?

4个回答

17
在这种特定情况下,为什么第一个比较方法(string.compare)有效而其他两个比较方法无效?
你的代码中存在不可见字符(特别是从左到右标记(感谢@MatthewWatson))。您可以使用任何十六进制编辑器查看它们:

enter image description here

这是string.Compare忽略的,而string.Equals没有忽略。您可以在文档中看到:

调用者注意事项:

字符集包括可忽略的字符。当 Compare(String, String) 方法执行基于区域性的比较时,它不考虑这些字符。例如,如果在 .NET Framework 4 或更高版本上运行以下代码,则使用软连字符(或 U+00AD)对“animal”和“ani-mal”进行区域性敏感比较表明两个字符串相等。


2
非常好。具体来说,字符串开头处的额外单个Unicode字符是一个“从左到右”的标记。 - Matthew Watson
感谢@Yuval和Matthew的回复。那么在我的情况下,应该采用什么样的比较方式呢?我应该坚持使用string.compare还是使用其他方法?请给出建议。 - Subhasis
@Subhasis 我建议坚持使用 string.Equals。在检查相等之前,您可以对字符串进行清理。 - Yuval Itzchakov
@XiaoPeng-Zenuml_com 这是一个隐藏字符。你可以在“THURSDAY”前面的图像中看到它。 - Yuval Itzchakov
@YuvalItzchakov,我的意思是你是怎么找到它的。Subhasis是发布了那张图片还是在其他地方分享了代码? - Devs love ZenUML
@XiaoPeng-Zenuml_com 我将他的代码复制粘贴到Notepad++中,并使用Hex插件查看了它。 - Yuval Itzchakov

3
< p >“ExecutionDay”字符串含有不可见字符,否则所有检查都将为true

< p >以下行返回不同的长度,分别为9和8

        Console.WriteLine(ExecutionDay.Length);
        Console.WriteLine("THURSDAY".Length);

1
你的开头有一个“隐形”字符。
string ExecutionDay = "‎THURSDAY";

这是从左到右标记,您可以使用以下方式进行检查:

int len = ExecutionDay.Length; // 9 instead of 8

并且

char ch = ExecutionDay[0]; // 8206

它已经在此网站的源代码中可见:<span class="str">"‎‎星期四"</span> - LInsoDeTeh
@LInsoDeTeh 嗯 &lrm; :-) - xanatos

0
简而言之,CompareTo方法是与文化相关的。例如ß(德语中的s sharp)
Console.WriteLine("ß Compare ss 1: " + ("ß".CompareTo("ss") == 0));
Console.WriteLine("ß Compare ss 2: " + (String.Compare("ß", "ss", StringComparison.Ordinal) == 0));
Console.WriteLine("ß equals ss: " + "ß".Equals("ss"));
Console.WriteLine("ß == ss: " + ("ß" == "ss"));

将打印出

ß Compare ss 1: True
ß Compare ss 2: False
ß equals ss: False
ß == ss: False

在您的情况下,您有相同但不同的字符串。通常我发现看到差异很有帮助,可以通过以下方式实现:
Console.WriteLine(
  string.Join(", ", 
    ExecutionDay
      .ToCharArray()
      .Select(o =((int)o).ToString(CultureInfo.InvariantCulture))
      .AsEnumerable()
  )
);

导致字符编号列表:

8206, 84, 72, 85, 82, 83, 68, 65, 89

Unicode 中的字符 8206从左到右标记


== 比较

这将仅比较值类型或基元类型的值。除此之外,它应该被用作引用比较。在 C# 中,字符串类型是特殊的,以下两个断言都将返回true

string ss = getinput();//"SS"
assertTrue("SS"=="SS");
assertTrue( ss =="SS");

在Java中,first会返回true,因为JIT运行时优化器从代码中收集所有唯一的字符串,并创建一个表格进行使用。第二个返回false,因为字符串只是不可变字符数组,如果由用户输入,则会使用新的内存空间,因此引用比较返回false。

C#实现Equals和相等运算符(==)的指南

Equals比较

== 不同,Equals方法只是在System.Object中定义的虚拟方法,并且由选择这样做的任何类进行了重写。 因此,将使用重写版本,并且对于字符串类型,这意味着将执行内容比较。

在重写Equals(Object)时,请遵循以下准则:
- 实现IComparable的类型必须重写Equals(Object)。 - 重写Equals(Object)的类型也必须重写GetHashCode;否则,哈希表可能无法正常工作。 - 您应该考虑实现IEquatable接口以支持强类型的相等测试。您的IEquatable.Equals实现应返回与Equals一致的结果。 - 如果您的编程语言支持运算符重载,并且您为给定类型重载了等号运算符,则还必须重写Equals(Object)方法以返回与等号运算符相同的结果。这有助于确保使用Equals(例如ArrayList和Hashtable)的类库代码的行为与应用程序使用等号运算符的方式一致。 C# 实现Equals方法

ComparedTo比较

注意

CompareTo 方法主要用于排序或字母顺序操作。当方法调用的主要目的是确定两个字符串是否相等时,不应使用该方法。要确定两个字符串是否相等,请调用 Equals 方法。

此方法使用当前区域设置执行单词(区分大小写和区域设置)比较。有关单词、字符串和序数排序的更多信息,请参阅 System.Globalization.CompareOptions。

来源:手册


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接