C# 如何在同一LINQ查询中使用'let'关键字并选择ValueTuple?

C# 如何在同一LINQ查询中使用'let'关键字并选择ValueTuple?,c#,linq,c#-7.0,C#,Linq,C# 7.0,理想情况下,我希望使用let关键字定义一些临时变量,以避免重复相同的Contains方法调用,使用这些值计算一些其他内容,然后返回ValueTuple。在一个链式表达式或查询表达式中可能出现这种情况吗?到目前为止,我只使用了两个表达式。哦,收藏当然是数不清的 using System; using System.Collections.Generic; using System.Linq; namespace FeaturesTest { class Program { cla

理想情况下,我希望使用let关键字定义一些临时变量,以避免重复相同的Contains方法调用,使用这些值计算一些其他内容,然后返回ValueTuple。在一个链式表达式或查询表达式中可能出现这种情况吗?到目前为止,我只使用了两个表达式。哦,收藏当然是数不清的

using System;
using System.Collections.Generic;
using System.Linq;

namespace FeaturesTest
{
  class Program
  {
    class Song
    {
      public string Artist { get; set; }
      public string Name { get; set; }
    }

    class User
    {
      public List<Song> FavouriteSongs { get; set; }
      public List<Song> HatedSongs { get; set; }
    }
    static void Main( string[] args )
    {
      List<Song> allSongs = new List<Song>
      {
        new Song{ Artist = "Atheist", Name = "Enthralled in Essence" },
        new Song{ Artist = "Death", Name = "Jealosy" },
        new Song{ Artist = "Cynic", Name = "Evolutionary Sleeper" },
        new Song{ Artist = "Ghost", Name = "Square Hammer" },
      };

      User bob = new User
      {
        FavouriteSongs = new List<Song>
        {
          allSongs[0],
          allSongs[1]
        },
        HatedSongs = new List<Song>
        {
          allSongs[3],
        }
      };

      var objects = from song in allSongs
                    let isFavourite = bob.FavouriteSongs.Contains( song )
                    let isHated = bob.HatedSongs.Contains( song )
                    select new
                    {
                      Artist = song.Artist,
                      Name = song.Name,
                      IsFavourite = isFavourite,
                      IsHated = isHated,
                      IsNeutral = !isFavourite && !isHated
                    };
      var tuples = objects.Select( o => (Artist: o.Artist,
                                         Name: o.Name,
                                         IsFavourite: o.IsFavourite,
                                         IsHated: o.IsHated,
                                         IsNeutral: o.IsNeutral) );

      Console.WriteLine( "Artist     Name                      Is Favourite    Is Hated   Is Neutral" );
      Console.WriteLine( "------     ----                      ------------    --------   ----------" );
      foreach( (string Artist, string Name, bool IsFavourite, bool IsHated, bool IsNeutral) in tuples )
      {
        Console.WriteLine( $"{Artist,-10} {Name,-25} {IsFavourite,-15} {IsHated,-10} {IsNeutral}" );
      }
    }
  }
}

除非我遗漏了什么:是的-只需投影一个命名的对象,而不是一个匿名对象:

var objects = from song in allSongs
              let isFavourite = bob.FavouriteSongs.Contains( song )
              let isHated = bob.HatedSongs.Contains( song )
              select (
                  song.Artist,
                  song.Name,
                  isFavourite,
                  isHated,
                  IsNeutral : !isFavourite && !isHated
              );
此外,对于foreach循环,您已经给出了名称,只需使用var,我认为这更容易阅读:

foreach( var t in tuples )
{
    Console.WriteLine( $"{t.Artist,-10} {t.Name,-25} {t.IsFavourite,-15} {t.IsHated,-10} {t.IsNeutral}" );
}

而且你的容器是易碎的。它将通过引用而不是内容来比较对象。在当前的示例中,这是可以的,但是如果对象是具有相同内容的不同实例,那么它就不会工作。为了纠正这个错误,实现Equals和GetHashCode。

该死,这是显而易见的!仍然不太习惯这种语法:关于Contains的观点也很好,没有首先想到它。@JerrySmith-很高兴它有帮助: