如何将谓词作为参数c#

时间:2017-06-26 13:53:45

标签: c# delegates predicate

如何将谓词传递给方法,但如果没有传递谓词,它还可以运行吗?我想也许是这样的,但它似乎不正确。

private bool NoFilter() { return true; }

private List<thing> GetItems(Predicate<thing> filter = new Predicate<thing>(NoFilter))
{
    return rawList.Where(filter).ToList();
}

2 个答案:

答案 0 :(得分:4)

private List<thing> GetItems(Func<thing, bool> filter = null)
{
    return rawList.Where(filter ?? (s => true)).ToList();
}

在此表达式中,s => true是回退过滤器,如果参数filter为空,则对其进行评估。它只需要列表的每个条目(作为s)并返回true

答案 1 :(得分:3)

这有两个部分。

首先,您需要调整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>返回类型,那么更改方法签名以返回{{1}几乎总是更好相反。如果你真的需要一个列表(通常你不需要),你可以在调用函数后调用IEnumerable<T>

此更改使您的方法更有用,为您提供一种更抽象的类型,与其他接口更兼容,并且它可能会在降低内存使用率和使用方面为您带来显着的性能提升。懒惰的评价。

这里最后一个补充是,如果你只关注ToList(),我们现在可以看到这个方法在基础IEnumerable字段之外根本没有提供太多价值。您可能会考虑转换为属性,如下所示:

rawItems

这仍然允许您的类型的消费者使用谓词(或不是),如果他们想要通过现有的public IEnumerable<T> Items {get {return rawList;}} 方法,同时还继续隐藏基础原始数据(您不能直接调用{{ 1}}等等。)