我可以获得扩展方法的 Func 对象吗
我有一个小型实用程序扩展方法,它对 IEnumerable
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
扩展方法直接传递给 NullableExtension
而不是将其包装在 lambda 中?
编辑
因为传入 Enumerable
扩展方法实际上很简洁,所以我删除了 NullableIntersect
(和其他)方法,只调用可为 null 的包装器直接地。
此外,正如 Anthony 指出的,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);
I have a small utility extension method that performs some null checks on some LINQ extension methods in IEnumerable<T>
. The code looks like this
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));
}
}
So, is there a way to pass in the IEnumerable<T>.Intersect
extension method to NullableExtension
directly rather than wrapping it in a lambda?
Edit
Because it is actually concise to pass in the Enumerable
extension method, I removed the NullableIntersect
(and other) methods and just call the nullable wrapper directly.
Also, as Anthony points out, the semantics of what an Empty enumerable should do is different depending on the extension method, i.e. Union
versus Intersect
. As such, I rename the NullableExtension
method to IgnoreIfNull
which better reflects the generic behavior.
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);
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
Intersect
是在静态类Enumerable
中定义的。您可以将其传递到您的方法中,如下所示注意:您可能担心空序列情况下逻辑的行为。例如,在
您定义的情况下,
output
包含{1, 4}
(second
的元素)。我可能期望first
被视为空序列,并且与second
的交集将导致空序列。最终,您需要决定您想要的行为。Intersect
is defined within static classEnumerable
. You can pass it into your method like belowNote: You might be concerned about the behavior of your logic in the case of a null sequence. For example, in the case of
You have defined it such that
output
contains{1, 4}
(the elements ofsecond
). I might expectfirst
to instead be treated as an empty sequence, and an intersection withsecond
would result in an empty sequence. Ultimately, that's for you to decide the behavior you desire.