【问题标题】:c# performance: type comparison vs. string comparisonc# 性能:类型比较与字符串比较
【发布时间】:2008-11-15 00:15:53
【问题描述】:

哪个更快?这个:

bool isEqual = (MyObject1 is MyObject2)

或者这个:

bool isEqual = ("blah" == "blah1")

找出哪个更快会很有帮助。显然,如果您像程序员经常做的那样将 .ToUpper() 应用于字符串比较的每一侧,则需要重新分配内存,这会影响性能。但是如果 .ToUpper() 不符合上述示例中的等式呢?

【问题讨论】:

    标签: c# .net performance string-comparison


    【解决方案1】:

    我有点困惑。

    正如其他答案所指出的,您正在比较苹果和橙子。 ::rimshot::

    如果您想确定一个对象是否属于某种类型,请使用is 运算符。

    如果您想比较字符串,请使用 == 运算符(或其他适当的比较方法,如果您需要一些花哨的东西,例如不区分大小写的比较)。

    一种操作与另一种操作相比有多快(没有双关语)似乎并不重要。


    仔细阅读后,我认为您想将字符串比较的速度与引用比较的速度(System.Object基类型中使用的比较类型)进行比较。

    如果是这样,那么答案是引用比较永远不会比任何其他字符串比较慢。 .NET 中的引用比较非常类似于比较 C 中的指针 - 尽可能快。

    但是,如果一个字符串变量s 的值是"I'm a string",但是下面的比较失败了,你会怎么想:

    if (((object) s) == ((object) "I'm a string")) { ... }
    

    如果您只是比较引用,这可能取决于s 的值是如何创建的。如果它最终没有被实习,它不会有与文字字符串相同的引用,所以比较会失败。因此,您可能会有更快的比较,但并不总是有效。这似乎是一个糟糕的优化。

    【讨论】:

    • 其他答案错过了关键点,即“is”运算符没有像提问者认为的那样做任何事情。
    【解决方案2】:

    根据最大化 .NET 性能一书 通话

    bool isEqual = String.Equals("test", "test");
    

    在性能上与

    相同
    bool isEqual = ("test" == "test");
    

    电话

    bool isEqual = "test".Equals("test");
    

    理论上比调用静态 String.Equals 方法慢,但我认为您需要比较几百万个字符串才能真正检测到速度差异。

    我给你的建议是这样的;不要担心哪种字符串比较方法更慢或更快。在正常的应用程序中,您永远不会注意到差异。你应该使用你认为最易读的方式。

    【讨论】:

    • Nicholas J. Wienholt 是作者吗?您认为这是推荐阅读吗?
    【解决方案3】:

    第一个用于比较类型而不是值。 如果要将字符串与不敏感的大小写进行比较,可以使用:

    string toto = "toto";
    string tata = "tata";
    
    bool isEqual = string.Compare(toto, tata, StringComparison.InvariantCultureIgnoreCase) == 0;    
    
    Console.WriteLine(isEqual);     
    

    【讨论】:

      【解决方案4】:

      你告诉我怎么样? :)

      this Coding Horror post 获取代码,并插入您的代码以代替他的算法进行测试。

      【讨论】:

        【解决方案5】:

        使用“==”运算符比较字符串会将字符串的内容与字符串对象reference进行比较。比较对象会调用对象的“Equals”方法来判断它们是否相等。 Equals 的默认实现是进行引用比较,如果两个对象引用都是相同物理对象,则返回 True。这可能比字符串比较快,但取决于被比较对象的类型。

        【讨论】:

          【解决方案6】:

          我假设比较您的第一个示例中的对象将尽可能快,因为它只是检查两个对象是否指向内存中的相同地址。

          正如已经多次提到的,也可以比较字符串上的地址,但是如果两个字符串是从不同的来源分配的,这不一定有效。

          最后,尽可能尝试根据类型比较对象通常是一种很好的形式。它通常是最具体的识别方法。如果您的对象需要用内存中的地址以外的东西来表示,则可以使用其他属性作为标识符。

          【讨论】:

          • 我想你也错过了“is”运算符的含义吗?
          【解决方案7】:

          如果我理解了这个问题,并且您真的想要将引用相等性与普通的“比较内容”进行比较:构建一个测试用例并调用 object.ReferenceEquals 与 a == b 进行比较。 p>

          注意:您必须了解差异是什么,并且在大多数情况下您可能无法使用参考比较。如果您确定这是您想要的,可能会快一点。您必须自己尝试并评估这是否值得麻烦..

          【讨论】:

            【解决方案8】:

            我觉得这些答案中的任何一个都不能解决实际问题。假设此示例中的字符串是类型的名称,我们试图查看比较类型名称或类型以确定它是什么更快。

            我把它放在一起,令我惊讶的是,检查类型名称字符串比我运行的每个测试中的类型快大约 10%。我故意使用最简单的字符串和类来看看是否有可能更快,结果证明这是可能的。不确定来自重度继承类的更复杂的字符串和类型比较。这当然是一个微操作,我想可能会在语言演变的某个时刻发生变化。

            在我的例子中,我正在考虑一个基于此名称切换的值转换器,但它也可以切换类型,因为每种类型都指定一个唯一的类型名称。值转换器会根据显示的项目类型找出要显示的字体真棒图标。

            using System;
            using System.Diagnostics;
            using System.Linq;
            
            namespace ConsoleApp1
            {
                public sealed class A
                {
                    public const string TypeName = "A";
                }
            
                public sealed class B
                {
                    public const string TypeName = "B";
                }
            
                public sealed class C
                {
                    public const string TypeName = "C";
                }
            
                class Program
                {
                    static void Main(string[] args)
                    {
                        var testlist = Enumerable.Repeat(0, 100).SelectMany(x => new object[] { new A(), new B(), new C() }).ToList();
            
                        int count = 0;
            
                        void checkTypeName()
                        {
                            foreach (var item in testlist)
                            {
                                switch (item)
                                {
                                    case A.TypeName:
                                        count++;
                                        break;
                                    case B.TypeName:
                                        count++;
                                        break;
                                    case C.TypeName:
                                        count++;
                                        break;
                                    default:
                                        break;
                                }
                            }
                        }
            
                        void checkType()
                        {
                            foreach (var item in testlist)
                            {
                                switch (item)
                                {
                                    case A _:
                                        count++;
                                        break;
                                    case B _:
                                        count++;
                                        break;
                                    case C _:
                                        count++;
                                        break;
                                    default:
                                        break;
                                }
                            }
                        }
            
                        Stopwatch sw = Stopwatch.StartNew();
                        for (int i = 0; i < 100000; i++)
                        {
                            checkTypeName();
                        }
                        sw.Stop();
                        Console.WriteLine(sw.Elapsed);
                        sw.Restart();
                        for (int i = 0; i < 100000; i++)
                        {
                            checkType();
                        }
                        sw.Stop();
                        Console.WriteLine(sw.Elapsed);
                    }
                }
            }
            

            【讨论】:

            • 10% 的差异接近统计误差。您能否尝试在checkTypeName() 之前运行checkType(),并确认性能差异仍然存在?
            • 我做了很多不同的方法,但总是一样的。对任何配置进行类型检查从未如此快速。
            猜你喜欢
            • 1970-01-01
            • 2011-03-27
            • 1970-01-01
            • 1970-01-01
            • 2010-10-25
            • 2016-04-27
            • 1970-01-01
            • 1970-01-01
            • 2021-08-05
            相关资源
            最近更新 更多