Могу ли я получить объект Func для метода Extension - PullRequest
0 голосов
/ 07 октября 2011

У меня есть небольшой метод расширения служебной программы, который выполняет некоторые нулевые проверки некоторых методов расширения LINQ в IEnumerable<T>. Код выглядит так

public static class MyIEnumerableExtensions
{
    // Generic wrapper to allow graceful handling of null values
    public static IEnumerable<T> NullableExtension<T>(this IEnumerable<T> first, IEnumerable<T> second, Func<IEnumerable<T>, IEnumerable<T>, IEnumerable<T>> f)
    {
        if (first == null && second == null) return Enumerable.Empty<T>();
        if (first == null) return second;
        if (second == null) return first;
        return f(first, second);
    }

    // Wrap the Intersect extension method in our Nullable wrapper
    public static IEnumerable<T> NullableIntersect<T>(this IEnumerable<T> first, IEnumerable<T> second)
    {
        // It'd be nice to write this as
        //
        //   return first.NullableExtension<T>(second, IEnumerable<T>.Intersect );
        //
        return first.NullableExtension<T>(second, (a,b) => a.Intersect(b));
    }
}

Итак, есть ли способ передать метод расширения IEnumerable<T>.Intersect в NullableExtension напрямую, а не заключать его в лямбду?

Редактировать

Поскольку на самом деле кратко передать метод расширения Enumerable, я удалил NullableIntersect (и другие) методы и просто вызвал обнуляемую оболочку напрямую.

Кроме того, как указывает Энтони, семантика того, что должен делать перечисляемый Empty, отличается в зависимости от метода расширения, то есть Union против Intersect. Поэтому я переименую метод NullableExtension в IgnoreIfNull, что лучше отражает общее поведение.

public static class MyIEnumerableExtensions
{
    // Generic wrappers to allow graceful handling of null values
    public static IEnumerable<T> IgnoreIfNull<T>(this IEnumerable<T> first, IEnumerable<T> second, Func<IEnumerable<T>, IEnumerable<T>, IEnumerable<T>> f)
    {
        if (first == null && second == null) return Enumerable.Empty<T>();
        if (first == null) return second;
        if (second == null) return first;
        return f(first, second);
    }

    public static IEnumerable<T> EmptyIfNull<T>(this IEnumerable<T> first, IEnumerable<T> second, Func<IEnumerable<T>, IEnumerable<T>, IEnumerable<T>> f)
    {
        return f(first ?? Enumerable.Empty<T>(), second ?? Enumerable.Empty<T>());
    }

}

// Usage example.  Returns { 1, 4 } because arguments to Union and Intersect are ignored
var items = new List<int> { 1, 4 };
var output1 = items.IgnoreIfNull(null, Enumerable.Union).IgnoreIfNull(null, Enumerable.Intersect);

// Usage example.  Returns { } because arguments to Union and Intersect are set to empty
var output2 = items.EmptyIfNull(null, Enumerable.Union).EmptyIfNull(null, Enumerable.Intersect);

1 Ответ

2 голосов
/ 07 октября 2011

Intersect определяется в статическом классе Enumerable.Вы можете передать его в свой метод, как показано ниже:

return first.NullableExtension<T>(second, Enumerable.Intersect);

Примечание: вы можете быть обеспокоены поведением вашей логики в случае нулевой последовательности.Например, в случае

List<int> first = null;
var second = new List<int> { 1, 4 };
var output = first.NullableIntersect(second).ToList();

Вы определили его так, что output содержит {1, 4} (элементы second).Я мог бы ожидать, что вместо first будет рассматриваться как пустая последовательность, а пересечение с second приведет к пустой последовательности.В конечном счете, именно вам решать, какое поведение вы желаете.

...