首页 > 解决方案 > 从 LINQ 查询返回命名元组

问题描述

我整天都在尝试,并且尝试过很多次,但没有运气。我有以下返回结果的 Linq 查询。

此查询返回 IEnumerable<sketchEntity>:

var temp = from entity in remainingEntities
            where entity.EndPoint.FuzzyEqual(matchPoint, _tolerance)
            select entity;

此查询返回 (IEnumerable<sketchEntity>, end)

var temp = (from entity in remainingEntities
            where entity.EndPoint.FuzzyEqual(matchPoint, _tolerance)
            select entity, ChainMatchType.End);

这些都不是我想要的。最终 IEnumerable 中的每个结果都需要是一个命名元组,每个元组都有一个 ISketchEntity 和 ChainMatchType:

List<(ISketchEntity sketchEntityName, ChainMatchType MatchName)>

我将在三个不同的时间进行类似的查询。

  1. 当某些类型的 ISketchEntities 与 EndPoint 匹配时。
  2. 当某些类型的 ISketchEntities 与 StartPoint 匹配时。
  3. 当某些类型的 ISketchEntities 与 CenterPoint 匹配时。

当我运行每个查询时,我想使用 Enum 添加结果类型来表示匹配类型。

public enum ChainMatchType
{
    Start,
    End,
    Center
}

我的计划是在返回结果之前将所有三个查询组合成一个结果。

如何格式化我的 LINQ 以将结果转换为命名元组:

Name            DataType
entity:         ISketchEntity
MatchType:      ChainMatchType

EDIT FuzzyEquals 是一个自定义扩展。它使用 +/- 容差比较两个点。我正在使用 CAD 数据,过去的历史告诉我,有时两个点可以接近到相等但没有完全相同的坐标。

    public static bool FuzzyEqual(this ISketchPoint sp, ISketchPoint other, double tolerance)
    {
        if (
            sp.X > other.X - tolerance && sp.X < other.X + tolerance &&
            sp.Y > other.Y - tolerance && sp.Y < other.Y + tolerance &&
            sp.Z > other.Z - tolerance && sp.Z < other.Z + tolerance
        )
            return true;
        return false;
    }

刚才看到之后,我想它可以简化为:

    public static bool FuzzyEqual(this ISketchPoint sp, ISketchPoint other, double tolerance)
    {
        return sp.X > other.X - tolerance && sp.X < other.X + tolerance &&
               sp.Y > other.Y - tolerance && sp.Y < other.Y + tolerance &&
               sp.Z > other.Z - tolerance && sp.Z < other.Z + tolerance;
    }

标签: c#linqtuples

解决方案


  • 我建议仅使用带有扩展方法的 Linq,并避免使用关键字样式from, in, where, select
    • 我承认这我个人的偏好——但 C# 的 Linq 关键字功能有些不协调,你几乎总是最终需要使用一些扩展方法(尤其是ToListand Include),并且混合使用关键字和扩展方法样式会使事情变得更难读。
  • 无论如何,您只需要在一个Select步骤中添加值元组,它可以是一个方法参数(尽管您不能轻易地参数化值元组成员名称 - 这是可能的,但超出了这个问题的范围)。

像这样:

List<( ISketchEntity sketchEntityName, ChainMatchType matchName )> withName = remainingEntities
    .Where( e => e.EndPoint.FuzzyEqual( matchPoint, _tolerance ) )
    .Select( e => ( sketchEntityName: e, matchName: matchName ) )
    .ToList()

作为参数化方法:

(我不知道是什么matchPoint_tolerance顺便说一句)。

public static List<( ISketchEntity sketchEntityName, ChainMatchType matchName )> Get2( this IEnumerable<ISketchEntity> entities, ChainMatchType matchType )
{
    // Precondition:
    if( entities is null ) throw new ArgumentNullException(nameof(entities));

    return entities 
        .Where( e => e.EndPoint.FuzzyEqual( matchPoint, _tolerance ) )
        .Select( e => ( sketchEntityName: e, matchName: matchType ) )
        .ToList()
}

推荐阅读