linq的let关键字比关键字更好吗?

时间:2009-03-13 09:25:39

标签: c# linq

我正在刷新LINQ,并试图理解let和使用into关键字之间的区别。到目前为止,就我的理解而言,let关键字似乎比into关键字更好。

into关键字实际上允许用户在投影后继续查询。 (只是想明确说明我不是指群组加入的那个。)

给定一系列名称,它允许人们执行以下操作:

var intoQuery =
  from n in names
  select Regex.Replace(n, "[aeiou]", "")
  into noVowel
  where noVowel.Length > 2
  select noVowel;

它会将select的结果放入noVowel变量中,然后允许其引入其他whereorderbyselect子句。创建noVowel变量后,n变量将不再可用。

另一方面,let关键字使用临时匿名类型允许您一次重用多个变量。

您可以执行以下操作:

var letQuery =
  from n in names
  let noVowel = Regex.Replace(n, "[aeiou]", "")
  where noVowel.Length > 2
  select noVowel;

noVoweln变量都可以使用(即使我在这种情况下没有使用它)。

虽然我可以看到差异,但我无法理解为什么人们会想要使用into关键字而不是let关键字,除非明确要确保以前的变量无法使用用于查询的后半部分。

那么,两个关键词存在的原因是否充分?

4 个答案:

答案 0 :(得分:83)

是的,因为他们正在做不同的事情,正如你所说的那样。

select ... into有效地隔离了整个查询,并允许您将其用作新查询的输入。我个人通常喜欢通过两个变量来做这件事:

var tmp = from n in names
          select Regex.Replace(n, "[aeiou]", "");

var noVowels = from noVowel in tmp
               where noVowel.Length > 2
               select noVowel;

(不可否认,在这种情况下,我会用两行中的点符号来做,但忽略了......)

通常,您不会希望查询前面部分的全部行李 - 即使用select ... into或根据上述示例将查询分成两部分时。这不仅意味着查询的早期部分不应该使用它们,它简化了正在发生的事情 - 当然这意味着每一步都可能发生的复制更少。

另一方面,当你想要保留其余的上下文时,let更有意义。

答案 1 :(得分:43)

主要区别是let将变量注入上下文/范围,其中into创建新的上下文/范围。

答案 2 :(得分:1)

想要了解数据库方面的差异,编写了2个实体框架查询。

  • from u in Users
    let noVowel = u.FirstName.Replace("a","").Replace("e","").Replace("i","")
    where noVowel.Length >5
    select new {u.FirstName, noVowel}
    
  • 进入

    from u in Users
    select u.FirstName.Replace("a","").Replace("e","").Replace("i","")
    into noVowel
    where noVowel.Length >5
    select noVowel
    

生成的SQL几乎相同。 SQL并不完美,在2个地方(where和select)重复相同的字符串处理代码。

SELECT 1 AS [C1], [Extent1].[FirstName] AS [FirstName], 
REPLACE(REPLACE(REPLACE([Extent1].[FirstName], N'a', N''), N'e', N''), N'i', N'') AS [C2]
FROM [dbo].[User] AS [Extent1]
WHERE ( CAST(LEN(REPLACE(REPLACE(REPLACE([Extent1].[FirstName], N'a', N''), N'e', N''), N'i', N'')) AS int)) > 5
GO

SELECT 
REPLACE(REPLACE(REPLACE([Extent1].[FirstName], N'a', N''), N'e', N''), N'i', N'') AS [C1]
FROM [dbo].[User] AS [Extent1]
WHERE ( CAST(LEN(REPLACE(REPLACE(REPLACE([Extent1].[FirstName], N'a', N''), N'e', N''), N'i', N'')) AS int)) > 5

这是LINQ-to-SQL生成的SQL

-- Region Parameters
DECLARE @p0 NVarChar(1000) = 'a'
DECLARE @p1 NVarChar(1000) = ''
DECLARE @p2 NVarChar(1000) = 'e'
DECLARE @p3 NVarChar(1000) = ''
DECLARE @p4 NVarChar(1000) = 'i'
DECLARE @p5 NVarChar(1000) = ''
DECLARE @p6 Int = 5
-- EndRegion
SELECT [t1].[FirstName], [t1].[value] AS [noVowel]
FROM (
    SELECT [t0].[FirstName], REPLACE(REPLACE(REPLACE([t0].[FirstName], @p0, @p1), @p2, @p3), @p4, @p5) AS [value]
    FROM [User] AS [t0]
    ) AS [t1]
WHERE LEN([t1].[value]) > @p6
GO

-- Region Parameters
DECLARE @p0 NVarChar(1000) = 'a'
DECLARE @p1 NVarChar(1000) = ''
DECLARE @p2 NVarChar(1000) = 'e'
DECLARE @p3 NVarChar(1000) = ''
DECLARE @p4 NVarChar(1000) = 'i'
DECLARE @p5 NVarChar(1000) = ''
DECLARE @p6 Int = 5
-- EndRegion
SELECT [t1].[value]
FROM (
    SELECT REPLACE(REPLACE(REPLACE([t0].[FirstName], @p0, @p1), @p2, @p3), @p4, @p5) AS [value]
    FROM [User] AS [t0]
    ) AS [t1]
WHERE LEN([t1].[value]) > @p6

似乎Linq-to-SQL比实体框架更智能,字符串进程只执行一次。

答案 3 :(得分:0)

leppie's answer的可视化版本。 可以看出,编译器在使用into的查询中产生错误,不像后者访问第一个变量那样。

enter image description here