【问题标题】:Incorrect number of arguments supplied for call to method 'Boolean Equals为调用方法“布尔等于”提供的参数数量不正确
【发布时间】:2015-09-22 09:34:47
【问题描述】:

为什么我得到一个参数异常,说我将错误数量的参数传递给 string.equals 方法?

我传递了三个参数,这应该是正确的。实际上它应该抛出编译时错误而不是运行时......

你看到错误了吗?

var translations = await (from l in context.Languages
                  join t in context.Translations on l.ISO639_ISO3166 equals t.ISO639_ISO3166
                  where string.Equals(l.ApplicationName, applicationName, StringComparison.InvariantCultureIgnoreCase)
                  select new Translation
                  {
                      Key = t.Key,
                      Text = t.Text
                  }).ToListAsync();

更新

Test Name:  GetTranslations
Test FullName:  TaaS.IntegrationTests.Tests.TranslationRepositoryTests.GetTranslations
Test Source:    C:\test\TaaS-WebApplication\TaaS.IntegrationTests\Tests\TranslationRepositoryTests.cs : line 17
Test Outcome:   Failed
Test Duration:  0:00:00,0473367

Result StackTrace:  
at System.Linq.Expressions.Expression.GetMethodBasedBinaryOperator(ExpressionType binaryType, Expression left, Expression right, MethodInfo method, Boolean liftToNull)
   at System.Linq.Expressions.Expression.Equal(Expression left, Expression right, Boolean liftToNull, MethodInfo method)
   at System.Data.Entity.Core.Objects.ELinq.LinqExpressionNormalizer.VisitMethodCall(MethodCallExpression m)
   at System.Linq.Expressions.EntityExpressionVisitor.Visit(Expression exp)
   at System.Linq.Expressions.EntityExpressionVisitor.VisitLambda(LambdaExpression lambda)
   at System.Linq.Expressions.EntityExpressionVisitor.Visit(Expression exp)
   at System.Linq.Expressions.EntityExpressionVisitor.VisitUnary(UnaryExpression u)
   at System.Linq.Expressions.EntityExpressionVisitor.Visit(Expression exp)
   at System.Linq.Expressions.EntityExpressionVisitor.VisitExpressionList(ReadOnlyCollection`1 original)
   at System.Linq.Expressions.EntityExpressionVisitor.VisitMethodCall(MethodCallExpression m)
   at System.Data.Entity.Core.Objects.ELinq.LinqExpressionNormalizer.VisitMethodCall(MethodCallExpression m)
   at System.Linq.Expressions.EntityExpressionVisitor.Visit(Expression exp)
   at System.Linq.Expressions.EntityExpressionVisitor.VisitExpressionList(ReadOnlyCollection`1 original)
   at System.Linq.Expressions.EntityExpressionVisitor.VisitMethodCall(MethodCallExpression m)
   at System.Data.Entity.Core.Objects.ELinq.LinqExpressionNormalizer.VisitMethodCall(MethodCallExpression m)
   at System.Linq.Expressions.EntityExpressionVisitor.Visit(Expression exp)
   at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter..ctor(Funcletizer funcletizer, Expression expression)
   at System.Data.Entity.Core.Objects.ELinq.ELinqQueryState.CreateExpressionConverter()
   at System.Data.Entity.Core.Objects.ELinq.ELinqQueryState.GetExecutionPlan(Nullable`1 forMergeOption)
   at System.Data.Entity.Core.Objects.ObjectQuery`1.<>c__DisplayClassc.<GetResultsAsync>b__a()
   at System.Data.Entity.Core.Objects.ObjectContext.<ExecuteInTransactionAsync>d__3d`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.<ExecuteAsyncImplementation>d__9`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Data.Entity.Utilities.TaskExtensions.CultureAwaiter`1.GetResult()
   at System.Data.Entity.Core.Objects.ObjectQuery`1.<GetResultsAsync>d__e.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Data.Entity.Utilities.TaskExtensions.CultureAwaiter`1.GetResult()
   at System.Data.Entity.Internal.LazyAsyncEnumerator`1.<FirstMoveNextAsync>d__0.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Data.Entity.Infrastructure.IDbAsyncEnumerableExtensions.<ForEachAsync>d__5`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at TaaS.Repository.TranslationRepository.<GetTranslationsAsync>d__2.MoveNext() in C:\_REPOSITORIES\taas-application\TaaS-WebApplication\TaaS.Repository\TranslationRepository.cs:line 20
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at TaaS.IntegrationTests.Tests.TranslationRepositoryTests.GetTranslations() in C:\_REPOSITORIES\taas-application\TaaS-WebApplication\TaaS.IntegrationTests\Tests\TranslationRepositoryTests.cs:line 45
Result Message: 
Test method TaaS.IntegrationTests.Tests.TranslationRepositoryTests.GetTranslations threw exception: 
System.ArgumentException: Incorrect number of arguments supplied for call to method 'Boolean Equals(System.String, System.String, System.StringComparison)'

【问题讨论】:

  • t.ISO639_ISO3166string 吗?
  • l.ApplicationName 一个字符串吗?
  • 如果它们不是字符串。它们都是编译时错误。 Elisabeth 发现运行时错误。
  • 提供完整的错误。
  • Boolean 的错误是像标题所说的那样,还是像问题所说的那样是 string.equals?

标签: c# linq


【解决方案1】:

首先,SQL 字符串比较不区分大小写,或者说,最常见的排序规则不区分大小写。

您根本不需要使用String.Equals。尝试在String.Equals调用的情况下执行您的查询。

如果由于某种原因查询未能返回结果,则参数或数据可能存在问题。您应该尝试直接执行等效的 SQL 语句,并检查是否有 匹配结果。

仅当基础列的排序规则被修改为对字符串敏感的排序规则时,字符串大小写才会成为问题。这将是非常不寻常的。事实上,困难的部分是让 LINQ to EF 进行区分大小写的查询。

至于错误本身,是因为String.Equals无法翻译成SQL造成的。 LINQ 本身执行查询,它只是一种语言。 LINQ 提供程序负责将查询转换为底层语言并执行它们。

一些提供程序,如 LINQ to SQL,会尽可能地解析,将结果加载到内存中,并将其传递给 LINQ to Object 以处理不受支持的操作。这通常会导致非常糟糕的性能。在您的情况下,您的查询会将所有翻译加载到内存中,然后尝试过滤它们。

另一方面,LINQ to EF 不允许这样做来防止性能问题。无法翻译的查询不会被执行。 String.Equals 特别是不能转换为 SQL,因为字符串比较是由特定于文化的排序规则控制的。没有等价于不变的文化。

如果您的表区分大小写,则必须更改用于比较的排序规则,例如更改为Latin1_CI_AS。这个SO question 描述了各种方法来做到这一点

【讨论】:

  • 感谢您不区分大小写的评论。这真的很有帮助!
  • 是的,我认为这是正确的。但是,我觉得它有点烦人。 Code First 不应该对数据库做出太多假设,您可以将 .Where(a == b) 作为 C# 条件并期望它匹配 a 和 b 不同的情况。无论如何,C# 规则都应该适用。
  • @StephenHolt 这是 LINQ to EF,而不是 Code First。此外,它精确地做出更少 的假设以避免生成意外的错误查询,就像 LINQ to SQL 所做的那样。最后,尝试将 C# 规则应用于完全不同的语言会导致性能错误。 LINQ 一开始就不是特定于 C# 的。
  • @StephenHolt 在 SQL 的情况下,这将是一场灾难,因为排序规则是 column 特定的。它会影响索引。尝试使用不同的排序规则会使索引无效并导致全表扫描
  • @StephenHolt,既然我们在谈论翻译,不同的语言在大小写之间有非常不同的匹配规则。土耳其语 I 就是一个完美的例子 - 有 dotted and dotless variants
【解决方案2】:

这是一个运行时错误,因为您可能会针对 Linq query provider 运行,它采用 expression 从您的 C# 代码创建的 C# 编译器并在运行时执行它。提供者可能无法翻译这种重载的 Equals。

尝试将您的 Linq 查询更改为:

(from l in context.Languages
join t in context.Translations on l.ISO639_ISO3166 equals t.ISO639_ISO3166).AsEnumerable()
.Where(l => string.Equals(l.ApplicationName, applicationName, StringComparison.InvariantCultureIgnoreCase))
.Select(new Translation
              {
                  Key = t.Key,
                  Text = t.Text
              }).ToListAsync();

【讨论】:

  • 虽然这是正确答案,但是否有任何 any Linq 查询提供程序需要支持的功能列表?我知道Canonical Functions,但 AFAIK 它们是 EF 特定的。许多人在从IEnumerabe&lt;T&gt; 切换到IQueryable&lt;T&gt; 时会感到困惑——一切都顺利编译,然后他们开始出现运行时错误。
  • 这取决于提供者。
  • 我将比较更改为“==”,因为我想再次记住,感谢@Panagiotis Kanavos,sql 比较不区分大小写。
  • 这不是一个好的答案,因为AsEnumerable() 会在内存中加载所有 行,然后尝试应用WHERE 条件而没有任何索引优势。它不会从 100K 表中加载例如 10 行,而是加载所有 100K 行
  • @PanagiotisKanavos 当然,我的意思是 LINQ 查询没有像 EF6 那样完全转换为 SQL。但是像上面这样的东西,只是为你自动制作的:) 看,我在开玩笑,但这确实是一个大问题,MS 团队将其设为默认功能。他们称之为混合查询执行或类似的东西。
【解决方案3】:

另一种方式(如果您坚持不区分大小写的比较)

var translations = await (from l in context.Languages
                  join t in context.Translations on l.ISO639_ISO3166 equals t.ISO639_ISO3166
                  where l.ApplicationName.Equals(applicationName,StringComparison.CurrentCultureIgnoreCase)
                  select new Translation
                  {
                      Key = t.Key,
                      Text = t.Text
                  }).ToListAsync();

注意:

l.ApplicationName.Equals(applicationName,StringComparison.CurrentCultureIgnoreCase)

但很可能你不需要这个,因为默认情况下 Linq to SQL 是

".. 不区分大小写,或者更确切地说,最常见的排序规则是 不区分大小写..."

【讨论】:

    【解决方案4】:

    在 Linq 中你需要使用 equals 的静态方法。改为这样做,它会起作用:

    where l.ApplicationName.Equals(applicationName, StringComparison.InvariantCultureIgnoreCase)
    

    【讨论】:

      【解决方案5】:

      如果您可以选择此选项,则只是另一种不区分大小写的比较方式:

      where l.ApplicationName.ToLower() == applicationName
      

      其中applicationName 可以作为applicationName.ToLower() 传递,所以这变成不区分大小写的比较:P

      【讨论】:

        猜你喜欢
        • 2014-07-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-04-03
        • 1970-01-01
        • 2015-05-14
        相关资源
        最近更新 更多