创建一个c# LINQ可选的Join扩展

本文关键字:Join 扩展 LINQ 一个 创建 | 更新日期: 2023-09-27 18:12:44

我正试图为Linq扩展,我可以使用可选的连接。我想我快找到了,但我还是少了点什么。你能发现吗?

public static IQueryable<T> OptionalJoin<T>(this IQueryable<T> source, bool condition, 
        Expression<IEnumerable<T>> TInner, 
        Expression<Func<T, object>> outerKeySelector, 
        Expression<Func<T, object>> innerKeySelector,
        Expression<Func<IQueryable<T>, IEnumerable<T>, object>> resultSelector)
    {
        return condition ? source.Join(TInner, outerKeySelector, innerKeySelector, resultSelector) : source;
    }

创建一个c# LINQ可选的Join扩展

可选连接实际上没有多大意义。您的返回类型是IQueryable<T>,如果您想返回原始集合,这是正确的。但如果你想加入一些东西,返回类型就必须改变。你也不能让一个方法根据运行时条件返回不同的编译时类型。

正因为如此,我认为你想做的事是不可能的。

我能想象这样的事情可以工作的唯一方法是,如果你有两个结果选择器:一个是当condition为真,另一个是当它为假。它们都将返回相同的类型。

还有,你的代码中有几个错误,我试图修复。

public static IQueryable<TResult> OptionalJoin<TSource, TInner, TKey, TResult>(
        this IQueryable<TSource> source,
        bool condition, 
        IQueryable<TInner> innerCollection,
        Expression<Func<T, TKey>> outerKeySelector, 
        Expression<Func<T, TKey>> innerKeySelector,
        Expression<Func<TSource, TInner, TResult>> trueResultSelector,
        Expression<Func<TSource, TResult>> falseResultSelector)
{
    return condition
        ? source.Join(innerCollection, outerKeySelector, innerKeySelector, trueResultSelector)
        : source.Select(falseResultSelector);
}

我想你会需要这样的东西:

public static IQueryable<TResult> OptionalJoin<TOuter, TInner, TKey, TResult>(
    this IQueryable<TOuter> outer,
    bool condition,
    IEnumerable<TInner> inner,
    Expression<Func<TOuter, TKey>> outerKeySelector,
    Expression<Func<TInner, TKey>> innerKeySelector,
    Expression<Func<TOuter, TInner, TResult>> joinResultSelector,
    Expression<Func<TOuter, TResult>> outerResultSelector)
{
    return condition
        ? outer.Join(inner,
            outerKeySelector,
            innerKeySelector,
            joinResultSelector)
        : outer.Select(outerResultSelector);
}

构建这样的操作符时,需要从内置操作符的签名开始,并尽可能保留参数签名。您正在有效地合并JoinSelect,因此从它们开始:

IQueryable<TResult> Join<TOuter, TInner, TKey, TResult>(
    this IQueryable<TOuter> outer,
    IEnumerable<TInner> inner,
    Expression<Func<TOuter, TKey>> outerKeySelector,
    Expression<Func<TInner, TKey>> innerKeySelector,
    Expression<Func<TOuter, TInner, TResult>> resultSelector)
public static IQueryable<TResult> Select<TSource, TResult>(
    this IQueryable<TSource> source,
    Expression<Func<TSource, TResult>> selector)

你的代码有一些签名错误。

另外,你可以很容易地减少我的答案,只使用T:

public static IQueryable<T> OptionalJoin<T, K>(
    this IQueryable<T> outer,
    bool condition,
    IEnumerable<T> inner,
    Expression<Func<T, K>> outerKeySelector,
    Expression<Func<T, K>> innerKeySelector,
    Expression<Func<T, T, T>> joinResultSelector)
{
    return condition
        ? outer.Join(inner,
            outerKeySelector,
            innerKeySelector,
            joinResultSelector)
        : outer;
}