当前位置: 首页 > 编程语言 > C#

LinqToSql奇怪行为分享

时间:2023-04-10 22:24:24 C#

LinqToSql奇怪行为我有如下代码:,t.姓名});//IQueryabletag2postsToDelete;foreach(标签中的标签标签){Debug.WriteLine(tag);tagToPosts=tagToPosts.Where(t=>t.Name!=tag.Name);}IQueryabletagToPostsToDelete=(fromt2pindataContext.TagToPostsjoindelintagToPostsont2p.Idequalsdel.Idselectt2p);dataContext.TagToPosts.DeleteAllOnSubmit(tagToPostsToDelete);其中tags是List-构造函数创建的标签列表,因此它们没有ID。我运行代码,在Debug上设置制动点,然后等待几个周期。然后我将WatchToPosts.ToList()放在监视窗口中以执行查询。在SQLProfiler中,我可以看到以下查询:execsp_executesqlN'SELECT[t0].[Id],[t1].[Name]FROM[dbo].[tblTagToPost]AS[t0]INNERJOIN[dbo].[tblTags]AS[t1]ON[t0].[TagId]=[t1].[Id]WHERE([t1].[Name]@p0)AND([t1].[Name]@p1)AND([t1].[名称]@p2)',N'@p0nvarchar(4),@p1nvarchar(4),@p2nvarchar(4)',@p0=N'tag3',@p1=N'tag3',@p2=N'tag3'我们可以看到每个参数argument都有循环中最后一个tag.Name的值。你有没有想出如何得到这个并让循环添加每次都有新条件的地方?我可以看到IQueryable在执行前只存储指向变量的指针。将您的foreach更改为:foreach(Tagtagintags){varx=tag.Name;tagToPosts=tagToPosts.Where(t=>t.Name!=x);这背后的原因是延迟评估和变量捕获。基本上,您在foreach语句中所做的并不是过滤掉可能看起来像它的结果。您正在构建一个依赖于要执行的某些变量的表达式树。重要的是要注意实际变量是在表达式树中捕获的,而不是捕获时的值。由于变量标记每次都被使用(并且它的范围是整个foreach,所以它不会在每次迭代结束时超出范围),它将被表达式的每个部分捕获并使用最后一个值因为它发生的一切。解决方案是使用一个在foreach内部作用域的临时变量,这样它会在每次迭代时超出作用域,而在下一次迭代时,它将被视为一个新变量。是的,Mehrdad的回答是正确的。当闭包在C#中捕获变量时(这是当您的“Where”lambda引用变量“tag”时发生的情况),编译器应用非常精确的规则来确定捕获的完成方式。如果捕获的变量在同一范围内,由周围的{和}括号确定,则该变量的值将按原样捕获。仅在变量超出范围时捕获对变量的引用。在您的原始帖子中,“tag”变量已通过循环循环到其最后一个值。但是,如果您按照Mehrdad的建议进行修改,那么您会在同一范围内捕获一个变量,因此该变量的各个值将嵌入到您的闭包中,从而为您提供所需的结果。顺便说一句,您可能会说,“是的,但是“标签”变量属于同一范围。”但事实并非如此,因为在幕后,编译器将for-each变成了这样的东西(非常粗糙,只是为了显示括号内发生的事情):{variterator=GetTheIterator();{while(iterator.MoveNext()){//这里是你的循环代码}}}重点是,for-each的迭代器将始终位于循环代码所在范围以外的范围内。以上就是C#学习教程《LinqToSql怪行为分享》的全部内容。如果对你有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处: