【问题标题】:Is there a solution that will convert the following LINQ Query Syntax to Method Syntax with Lambdas [duplicate]是否有一种解决方案可以将以下 LINQ 查询语法转换为使用 Lambda 的方法语法 [重复]
【发布时间】:2020-06-23 18:59:30
【问题描述】:

是否有工具、流程或解决方案可以将以下 LINQ 查询语法转换为方法

        public static IEnumerable<TResult> LeftOuterJoin<TSource, TInner, TKey, TResult>(this IEnumerable<TSource> source, IEnumerable<TInner> other, 
        Func<TSource, TKey> func, Func<TInner, TKey> innerkey, Func<TSource, TInner, TResult> res)
    {
        return from f in source
               join b in other on func.Invoke(f) equals innerkey.Invoke(b) into g
               from result in g.DefaultIfEmpty()
               select res.Invoke(f, result);
    }

【问题讨论】:

  • Resharper,右键,转换为 linq 链方法,但是有些时候查询语法更容易阅读
  • @TheGeneral ...第 3 步,卸载 ReSharper。
  • @Oliver 我希望您不要说 resharper 速度慢、占用资源、不稳定且不适合大型项目,因为它不断的单线程定价过高的遗留代码库。因为你是完全正确的,我不能和你争论..
  • @MaximKosov 这个页面是我的起点。那里只有 Linqpad 对我来说很有趣。

标签: c# linq entity-framework-core


【解决方案1】:

GroupJoin 是您使用 SelectMany 取消分组的 Left-Outer-Join

示例:有一名或多名学生的学校

  • 学校 A 有学生 1、2、7
  • B 校有 3、5 名学生,
  • C 校没有学生
  • D 校有 4、6 名学生,

GroupJoin 只会给出上述内容:拥有零个或多个学生的学校

显然你想要以下结果。

School.Id | Student.Id   Student.SchoolId
   A      |     1           A
   B      |     3           B
   A      |     2           A
   C      |   (null)
   B      |     5           B
   D      |     4           D
   D      |     6           D

恕我直言,我更喜欢第一个查询(学校及其学生),但嘿,这是你的设计。

public static IEnumerable<TResult> LeftOuterJoin<TSource, TInner, TKey, TResult>(
    this IEnumerable<TSource> outerCollection,
    IEnumerable<TInner> innerCollection, 
    Func<TSource, TKey> outerKeySelector,
    Func<TInner, TKey> innerkeySelector,
    Func<TSource, TInner, TResult> resultSelector)
{
    return outerCollection.GroupJoin(innnerCollection,
    outerElement => outerKeySelector(outerElement),
    innerElement => innerKeySelector(innerElement),
    (outerElement, innerElementsOfThisOuterElement) => new
    {
        OuterElement = outerElement,
        InnerElements = innerElementsOfThisOuterElement,
    })

    // result: a sequence of outerElements, each with their zero or more innerElements
    // use SelectMany to ungroup:
    .SelectMany(group => group.InnerElements, // = parameter collectionSelector

    // parameter resultSelector:
    (group, innerElement) => resultSelector(group.OuterElement, innerElement));
}

言辞:

从innerCollection 中的每个元素,计算一个innerKey,使用innerKeySelector。

从outerCollection的每个元素中找到属于这个outerElement的所有innerElements,通过计算outerKey,使用outerKeySelector并获取所有innerKey等于outerKey的innerElements。

结果是一个组:一个包含 OuterElements 的组,每个组都有零个或多个 InnerElements。

取消组合:从每个组中取出 group.OuterElement 及其每个 InnerElement。对于每个组合(outerElement、innerElement),使用 ResultSelector 创建一个 TResult

如果你只使用一次,我不会为此做一个特殊的方法。只需写 GroupJoin,然后是 SelectMany:

var result = ...
    .GroupJoin(...)
    .SelectMany(...)

如果您经常使用它,并且计划创建一个单独的方法,请考虑使该方法更高效:

public static IEnumerable<TResult> LeftOuterJoin<TSource, TInner, TKey, TResult>(
    this IEnumerable<TSource> outerCollection,
    IEnumerable<TInner> innerCollection, 
    Func<TSource, TKey> outerKeySelector,
    Func<TInner, TKey> innerkeySelector,
    Func<TSource, TInner, TResult> resultSelector)
{
    var innerLookup = innerCollection.ToLookup(innerKeySelector);

    foreach (var outerElement in outerCollection)
    {
        var outerKey = outerKeySelector(outerElement);
        var innerElementsOfThisOuterElement = innerLookup[outerKey];
        // might be empty!

        // for every inner, return combinatino of (outer, inner)
        // if inner empty: return (outer, null)
        var innerEnumerator = innerElementsOfThisOuterElement.GetEnumerator();
        if (innerEnumerator.MoveNext())
        {
            // there is at least one inner
            yield return resultSelector(outerElement, innerEnumerator.Current);

            // do the rest:
            while enumerator.MoveNext())
                yield return resultSelector(outerElement, innerEnumerator.Current);
        }
        else
        {
             // no inner
                            yield return resultSelector(outerElement, null);
        }
    }
}

【讨论】:

  • 谢谢。现在我对这个主题有了更好的理解。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-15
  • 1970-01-01
  • 1970-01-01
  • 2021-06-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多