#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;
}
Я надеюсь, что это поможет.