【问题标题】:String[].Count() giving strange resultString[].Count() 给出奇怪的结果
【发布时间】:2014-09-18 08:46:15
【问题描述】:

我正在调试一些代码,遇到了这个奇怪的场景。一个方法接受一个String[] 变量,它首先检查该变量是否为null...

protected override CommandResult OnExecute(DateTime closeOfBusinessDate, 
                                                                string[] verbs)
        {
            if (verbs == null)
            {
                throw new ArgumentNullException("verbs");
            }

我们通过了这一行,接下来检查它以确保变量的值不超过一个......

 if (verbs.Count() > 1)
     {
        throw new ArgumentException("Only single verb supported.", "verbs");
     }

这是非常基本的东西,但在调试过程中,我看到了这个结果......

如您所见,Count()1,但检查结果仍为 if (verbs.Count() > 1) 的 true,谁能解释一下?也许我遗漏了一些明显的东西。

编辑:添加输出

在输出窗口可以看到,值为1

【问题讨论】:

  • 尝试在 if 语句之前打印 verbs.Count()
  • 能否请您发布动词数组?谢谢!
  • 我无法评论奇怪的行为,但我必须问该方法是否只需要一个动词,为什么它需要一个数组?
  • 如果代码正是您显示的内容,这很奇怪,特别是因为 AFAIK 数组不会在不更改引用的情况下更改其大小(在并发访问的情况下)。顺便说一句,为什么.Count() 而不是.Length
  • .Count() 调用是否真的绑定到了Enumerable.Count<T>(this IEnumerable<T>) 扩展方法?

标签: c# visual-studio debugging visual-studio-2013


【解决方案1】:

考虑以下代码:

    static void Example()
    {
        var verbs = new string[] { null, null };
        checkBerbs(verbs);
    }

    static void checkVerbs(string[] verbs)
    {
        if (verbs.Count() > 1)
        {
            mutateArray(ref verbs); //this would run another thread --> race condition
            throw new ArgumentException();
        }
    }

    private static void mutateArray(ref string[] verbs)
    {
        verbs = new string[] { null };
    }

这是一种可能的情况。不知道您的代码的全部范围我不确定这是否可能。显然mutateArray 将在另一个线程上运行,并且您将遇到竞争条件。也许锁定 verbs 可以让您知道这是一些并发问题。

【讨论】:

  • 如果您在 Example() 中 mutate 数组但作为方法参数传递的数组是按值传递的(那么如果相同的变量与 ref 一起传递给另一个方法...第一种方法“接收”的数组不会改变。
  • 是的,是一样的。如果您在 checkVerbs() 中调用 mutateArray() ,那么您所描述的可能会发生(但我想 OP 在这种情况下不会感到惊讶......)。如果在 Example() 中调用 mutateArray() 则 checkVerbs() 接收到的数组不会受到影响。
【解决方案2】:

如果代码实际上调用了Enumerable.Count 扩展方法并且没有任何技巧,问题是你假设下一个要执行的语句是throw 语句。

最有可能导致调试器出现在一个位置(即使它不是)的两种情况是:

  1. 在启用优化的情况下进行编译(非常常见;Release 配置中的默认设置)。
  2. 使用不能正确更新调试信息的 IL 重写工具(不是特别常见)。

使用 Debug 配置重新编译或运行代码可能会显示throw 语句实际上未到达。

【讨论】:

  • +1000^0 给你,如果他没有去看看指令是否会被执行...
  • @AdrianoRepetti 最初的问题和@christiandev 的任何评论都没有表明他跨过了throw 声明以验证它是否真的被抛出,也没有暗示测试是用优化代码设置已禁用(例如 Debug 配置)。
【解决方案3】:

Count 不是这样工作的。请改用verbs.Length

【讨论】:

    【解决方案4】:

    我不确定我能告诉你为什么你会看到这个结果,但我可以建议一个解决方法:使用 verbs.Length 而不是 verbs.Count()。在这种情况下,Count() 是一种 LINQ 方法,而 Length 是数组属性,它将告诉您数组中的项目数。

    【讨论】:

    • 显然 Count() 给出了错误的答案。它是一段比 Length 更昂贵的代码,它给出了正确的答案。所以实际上,Count() 是错误的......
    猜你喜欢
    • 2015-04-17
    • 2013-08-20
    • 2019-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多