【问题标题】:String.Equals vs String.Compare vs "==" in Action. Explanation neededString.Equals vs String.Compare vs "==" 在行动。需要解释
【发布时间】:2015-06-17 07:31:00
【问题描述】:

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

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) 有效,而其他两种比较方法在这种特殊情况下无效?

【问题讨论】:

    标签: c# .net string string-comparison


    【解决方案1】:

    为什么第一个比较(string.compare)和其他两个比较有效 比较方法在这种特殊情况下不起作用

    您的代码中有不可见的字符(特别是Left-to-Right mark(感谢@MatthewWatson))。您可以使用任何十六进制编辑器查看它们:

    string.Compare 忽略了这一点,而 string.Equals 则没有。你可以在the docs看到它:

    来电者须知:

    字符集包括可忽略的字符。这 Compare(String, String) 方法 不考虑此类字符时 它执行文化敏感的比较。例如,如果 以下代码在 .NET Framework 4 或更高版本上运行,a “动物”与“动物”的文化敏感比较(使用软 连字符或 U+00AD) 表示两个字符串是等价的。

    【讨论】:

    • 很好看。具体来说,字符串开头的额外单个 Unicode 字符是 "Left-to-right" mark
    • 感谢您的回复@Yuval 和 Matthew。所以在我的情况下,什么应该是正确的比较方式。我应该坚持使用 string.compare 还是使用其他任何东西。请建议。
    • @Subhasis 我建议坚持使用string.Equals。您可以在检查相等性之前清理字符串。
    • @XiaoPeng-Zenuml_com 是隐藏角色。您可以在“THURSDAY”前面的图片中看到它。
    • @YuvalItzchakov,我的意思是你是怎么找到它的。 Subhasis 是发布了这张图片还是在其他地方分享了代码?
    【解决方案2】:

    ExecutionDay 字符串包含不可见字符,否则所有检查都为真

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

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

    【讨论】:

      【解决方案3】:

      你的开头有一个“隐形”字符

      string ExecutionDay = "‎THURSDAY";
      

      它是LEFT-TO-RIGHT MARK。您可以通过以下方式进行检查:

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

      char ch = ExecutionDay[0]; // 8206
      

      【讨论】:

      • 在本站源码中已经可以看到:"‎‎THURSDAY"
      • @LInsoDeTeh 是的 ‎ :-)
      【解决方案4】:

      简而言之,CompareTo 依赖于文化。例如ß (s sharp from German):

      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
      

      其中字符 8206 在 unicode 中是 left-to-right mark


      == 比较

      仅当它是值类型或原语时才会比较值。除此之外,它是并且应该用作参考比较。在 C# 中,类型 string 是特殊的,以下两个断言都会产生 true

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

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

      C# Guidelines for Implementing Equals and the Equality Operator (==)

      等于比较

      ==不同的是,Equals 方法只是在 System.Object 中定义的一个虚拟方法,并且会被任何选择这样做的类覆盖。因此将使用覆盖的版本,如果是字符串类型,这意味着将进行内容比较。

      在覆盖 Equals(Object) 时遵循以下准则:

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

      C# Implementing the Equals Method

      ComparedTo 比较

      注意

      CompareTo 方法主要用于 用于排序或字母排序操作。不应该在什么时候使用 方法调用的主要目的是确定两个 字符串是等价的。判断两个字符串是否 等价,调用 Equals 方法。

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

      来源:Manual

      【讨论】:

        猜你喜欢
        • 2012-03-22
        • 2021-12-31
        • 2011-08-13
        • 1970-01-01
        • 2015-08-02
        • 1970-01-01
        • 1970-01-01
        • 2018-07-10
        • 2011-02-22
        相关资源
        最近更新 更多