当使用double、float或decimal而不是int时,LINQ查询不会编译



考虑以下简化示例,该示例是以代码为模型的,该代码搜索对象列表,并通过为每个对象分配分数来对其进行排序,以尝试计算相关性(真实代码中的分数细节与此无关):

public class MyClass
{
public string UserName { get; set; }
public string UserDescription { get; set; }
}
public static void QueryTest()
{
var somequerytext = "test";
var accounts = new List<MyClass>();
var resultsViaInt = accounts.Where( ( MyClass acct, int score ) => 
MatchInt( acct.UserName, somequerytext, ref score, 2 ) ||
MatchInt( acct.UserDescription, somequerytext, ref score, 1 ) 
)
.Select( ( acct, score ) => new { result = acct, score = score } )
.OrderBy( x => x.score )
.Select( x => x.result )
.ToList();
var resultsViaDouble = accounts.Where( ( MyClass acct, double score ) => 
MatchDouble( acct.UserName, somequerytext, ref score, 2.0 ) ||
MatchDouble( acct.UserDescription, somequerytext, ref score, 1.0 )
)
.Select( ( MyClass acct, double score ) => new { result = acct, score = score } )
.OrderBy( x => x.score )
.Select( x => x.result )
.ToList();
}

public static bool MatchInt( string haystack, string needle, ref int score, int weight )
{
if ( haystack.Contains( needle ) )
{
score = score + weight;
return true;
}
return false;
}
public static bool MatchDouble( string haystack, string needle, ref double score, double weight )
{
if ( haystack.Contains( needle ) )
{
score = score + weight;
return true;
}
return false;
}

出于某种原因,编译器在QueryTest()中为第二个查询抛出以下错误:

对于"账户"变量:

'List<MyClass>' does not contain a definition for 'Where' and the best extension method overload 'Queryable.Where<MyClass>(IQueryable<MyClass>, Expression<Func<MyClass, bool>>)' requires a receiver of type 'IQueryable<MyClass>'

对于查询本身内部的lambda表达式:

Delegate 'Expression<Func<MyClass, bool>>' does not take 2 arguments

如果我尝试使用doublefloatdecimal,我会得到相同的错误。然而,使用int是可行的。我可以使用稍大的整数而不是双精度来完成其余的工作,但我想了解一下为什么上面的代码不能编译。

第二个错误看起来很奇怪,因为第一个查询的等价部分被(正确地)检测为<Func<MyClass, int, bool>>,而有错误的查询完全缺少对在中间参数的任何引用。

为什么它只适用于int

我认为这与您想要的非常接近。

var resultsViaDouble = accounts
.Select(acct =>
{
double score = 0;
return new
{
match = MatchDouble(acct.UserName, somequerytext, ref score, 2.0) || MatchDouble(acct.UserDescription, somequerytext, ref score, 1.0),
score = score,
acct = acct
};
})
.Where(x => x.match)
.OrderBy(x => x.score)
.Select(x => x.acct)
.ToList();

至于OP中的方法有什么问题,我认为这些评论已经足够彻底地解释了。

Where方法的过载是:

public static IEnumerable<TSource> Where<TSource>(
this IEnumerable<TSource> source,
Func<TSource, int, bool> predicate
)

(List<MyClass>是IEnumerable)

CCD_ 11参数表示连续中元素的索引

double参数不存在这种过载

所以你在这里错误地使用了int score


我建议像这样转换代码:

public static double MatchDouble(string haystack, string needle, double weight )
{
return haystack.Contains( needle ) ? weight : 0;
}
var resultsViaInt = accounts
.OrderBy( 
acct => MatchDouble( acct.UserName, somequerytext, 2.0 ) +
MatchDouble( acct.UserDescription, somequerytext, 1.0 )  
)
.ToList();

最新更新