c# - 为什么我的绑定(bind)参数都相同(使用 Linq)?

标签 c# linq linq-to-sql binding

当我运行这段代码时:

string[] words = new string[] { "foo", "bar" };
var results = from row in Assets select row;
foreach (string word in words)
{
    results = results.Where(row => row.Name.Contains(word));
}

我得到这个 SQL:

-- Region Parameters
DECLARE @p0 VarChar(5) = '%bar%'
DECLARE @p1 VarChar(5) = '%bar%'
-- EndRegion
SELECT ... FROM [Assets] AS [t0]
WHERE ([t0].[Name] LIKE @p0) AND ([t0].[Name] LIKE @p1)

请注意,@p0@p1 都是 bar,而我希望它们是 foo 并且

我猜 Linq 以某种方式绑定(bind)了对变量 word 的引用,而不是对 word 当前引用的字符串的引用?避免此问题的最佳方法是什么?

(此外,如果您对此问题有更好的标题建议,请在评论中提出。)

请注意,我也使用常规 Linq 尝试过此操作,结果相同(您可以将其直接粘贴到 Linqpad 中):

string[] words = new string[] { "f", "a" };
string[] dictionary = new string[] { "foo", "bar", "jack", "splat" };
var results = from row in dictionary select row;
foreach (string word in words)
{
    results = results.Where(row => row.Contains(word));
}
results.Dump();

转储:

bar
jack
splat

最佳答案

您正在使用所谓的“闭包”,这意味着您正在定义一个在其主体中使用局部变量的匿名函数(您的 lambda)。具体来说,您正在“关闭”循环变量 word。闭包引起的问题是由延迟执行引起的,这意味着 lambda 的主体不是在您定义它时运行,而是在它被调用时运行。

正因为如此,您几乎永远不想关闭循环变量。由于延迟执行,lambda 中变量的值将是 执行 lambda 时的值。对于在循环内声明并在循环外调用的 lambda,这意味着它将始终具有循环中的最后一个值。

为了抵消这种情况,请使用在循环内声明的局部变量。这将导致它在那个时间点捕获值并将一个新变量传递给创建的每个 lambda。像这样:

string[] words = new string[] { "foo", "bar" }; 
var results = from row in Assets select row; 
foreach (string word in words) 
{ 
    string tempWord = word;

    results = results.Where(row => row.Name.Contains(tempWord)); 
} 

关于c# - 为什么我的绑定(bind)参数都相同(使用 Linq)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2827054/

相关文章:

c# - 使用 lambda 表达式连接表

c# - 单击网格列时出现异常

c# - EF Core 一对多与 IQueryable

c# - 将 Linq 表达式添加到表达式列表的方法

c# - 如何为属性定义别名

c# - 如何在不丢失数据的情况下重命名 Entity Framework 5 Code First 迁移中的数据库列?

c# - 在动态 Asp :net Table 上添加必需的验证器

c# - F# Array.choose id 在 C# 中等效

sql - 检查时间范围重叠,watchman 问题 [SQL]

c# - Linq to SQL 数据库上下文管理