这个问题有两个部分。
首先,您需要调整 NoFilter()
函数以与 Predicate<T>
兼容。注意,后者是泛型的,但前者不是。将 NoFilter()
更改为以下内容:
private bool NoFilter<T>(T item) { return true; }
我知道你从不使用泛型类型参数,但是这是必要的,以使其与你的谓词签名兼容。
有趣的是,你也可以通过以下方式定义NoFilter
:
private Predicate<T> NoFilter = x => true
现在是第二部分:我们可以考虑使用新的通用方法作为
GetItems()
的默认参数。这里有一个技巧,你只能使用
常量。虽然
NoFilter()
永远不会改变,但从编译器的角度来看,它并不完全等同于正式的常量。实际上,你只能使用
一种可能的常量:
null
。这意味着你的方法签名必须像这样:
private List<thing> GetItems(Predicate<thing> filter = null)
然后你可以在函数开头检查 null
并将其替换为 NoFilter
:
private List<thing> GetItems(Predicate<thing> filter = null)
{
if (filter == null) filter = NoFilter;
return rawList.Where(filter).ToList();
}
如果您想在调用方法时显式地传递这个参数,可以这样做:
var result = GetItems(NoFilter);
这应该完全回答了最初的问题,但我不想就此停止。让我们深入了解一下。
既然您现在已经需要if
条件,那么此时我倾向于完全删除NoFilter<T>()
方法,并只执行以下操作:
private IEnumerable<thing> GetItems(Predicate<thing> filter = null)
{
if (filter == null) return rawList;
return rawList.Where(filter);
}
请注意,我还更改了返回类型并删除了最后的
ToList()
调用。如果你发现自己在函数末尾调用
ToList()
以匹配
List<T>
返回类型,那么更改方法签名为返回
IEnumerable<T>
几乎总是
更好的选择。如果你真的需要一个列表(通常不需要),你仍然可以在调用函数后调用
ToList()
。
这个改变使你的方法更加有用,给你一个更抽象的类型,更适合其他接口,并且可能会带来显著的性能提升,无论是在降低内存使用方面还是在惰性求值方面。
最后一个补充是,如果你只使用
IEnumerable
,我们可以看到这个方法实际上除了基本的
rawItems
字段之外没有太多价值。你可以考虑将其转换为属性,像这样:
public IEnumerable<T> Items {get {return rawList;}}
这仍然允许您的类型的消费者使用
.Where()
方法来使用谓词(或不使用),同时继续隐藏底层的原始数据(您不能直接调用
.Add()
等)。
NoFilter
定义为Predicate<things>
并传递它。 - SinatrGetItems() { return GetItems(NoFilter); }
。 - Leenew Predicate<thing>(NoFilter)
在代码编译时就被解析了。现在你这么说,我才明白。谢谢。 - Fabulous