Создание дополнительного расширения соединения C # LINQ

#c# #linq

#c# #linq

Вопрос:

Я пытаюсь создать расширение для 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;
    }
 

Ответ №1:

Необязательное соединение на самом деле не имеет особого смысла. Ваш возвращаемый тип — IQueryable<T> , что правильно, если вы хотите вернуть исходную коллекцию. Но если вы хотите присоединить к нему что-то, возвращаемый тип должен измениться. И у вас не может быть метода, который возвращает разные типы во время компиляции на основе условия времени выполнения.

Из-за этого я думаю, что то, что вы пытаетесь сделать, невозможно.

Единственный способ, которым я могу представить, что что-то подобное могло бы сработать, это если бы у вас было два селектора результатов: один, когда condition true, а другой, когда false . И оба они будут возвращать один и тот же тип.

Кроме того, в вашем коде есть несколько ошибок, которые я пытался исправить.

 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);
}
 

Ответ №2:

Я думаю, вам понадобится что-то вроде этого:

 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);
}
 

При создании подобных операторов вам нужно начинать с подписей встроенных операторов и сохранять подписи параметров, где это возможно. Вы эффективно объединяетесь Join с Select ними, поэтому начните с них:

 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;
}
 

Я надеюсь, что это поможет.