有什么办法可以否定谓词吗?

发布于 2024-08-19 15:55:17 字数 345 浏览 8 评论 0原文

我想做这样的事情:

List<SomeClass> list1 = ...
List<SomeClass> list2 = ...
Predicate<SomeClass> condition = ...

...

list2.RemoveAll (!condition);

...

list2.AddRange (list1.FindAll (condition));

但是,这会导致编译器错误,因为 ! 无法应用于 Predicate。有什么办法可以做到这一点吗?

I want to do something like this:

List<SomeClass> list1 = ...
List<SomeClass> list2 = ...
Predicate<SomeClass> condition = ...

...

list2.RemoveAll (!condition);

...

list2.AddRange (list1.FindAll (condition));

However, this results in a compiler error, as ! can't be applied to Predicate<SomeClass>. Is there any way to do this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

徒留西风 2024-08-26 15:55:17

您可以使用 lambda 表达式就地定义匿名委托,该委托是否定谓词结果的结果:

list.RemoveAll(x => !condition(x));    

另一种选择:

static Predicate<T> Negate<T>(Predicate<T> predicate) {
     return x => !predicate(x);
}

用法:

// list is List<T> some T
// predicate is Predicate<T> some T
list.RemoveAll(Negate(predicate));

list.RemoveAll(!condition) 不起作用的原因是委托上没有定义 ! 运算符。这就是为什么您必须根据上面所示的条件定义一个新委托。

You could use a lambda expression to define an anonymous delegate inplace that is the result of negating the result of the predicate:

list.RemoveAll(x => !condition(x));    

Another option:

static Predicate<T> Negate<T>(Predicate<T> predicate) {
     return x => !predicate(x);
}

Usage:

// list is List<T> some T
// predicate is Predicate<T> some T
list.RemoveAll(Negate(predicate));

The reason that list.RemoveAll(!condition) does not work is that there is no ! operator defined on delegates. This is why you must define a new delegate in terms of condition as shown above.

我喜欢麦丽素 2024-08-26 15:55:17

这实际上是可能的,但可能与您习惯的形式略有不同。在 .NET 中,lambda 表达式可以解释为委托解释为 表达式树。在表达式树上执行 NOT 操作相对简单。

以下是使用您的代码作为起点的示例:

namespace Sample
{
    using System;
    using System.Collections.Generic;
    using System.Linq.Expressions;

    internal class ExpressionSample
    {
        private static Expression<TDelegate> Negate<TDelegate>(Expression<TDelegate> expression)
        {
            return Expression.Lambda<TDelegate>(Expression.Not(expression.Body), expression.Parameters);
        }

        private static void Main()
        {
            // Match any string of length 2 or more characters
            Expression<Predicate<string>> expression = (s) => s.Length > 1;

            // Logical negation, i.e. match string of length 1 or fewer characters
            Expression<Predicate<string>> negatedExpression = ExpressionSample.Negate(expression);

            // Compile expressions to predicates
            Predicate<string> predicate = expression.Compile();
            Predicate<string> negativePredicate = negatedExpression.Compile();

            List<string> list1 = new List<string> { string.Empty, "an item", "x", "another item" };
            List<string> list2 = new List<string> { "yet another item", "still another item", "y", string.Empty };

            list2.RemoveAll(negativePredicate);
            list2.AddRange(list1.FindAll(predicate));

            list2.ForEach((s) => Console.WriteLine(s));
        }
    }
}

This is actually possible, but maybe in a slightly different form than you're used to. In .NET, lambda expressions can either be interpreted as delegates OR as expression trees. It is relatively straightforward to perform a NOT operation on an expression tree.

Here is a sample using your code as a starting point:

namespace Sample
{
    using System;
    using System.Collections.Generic;
    using System.Linq.Expressions;

    internal class ExpressionSample
    {
        private static Expression<TDelegate> Negate<TDelegate>(Expression<TDelegate> expression)
        {
            return Expression.Lambda<TDelegate>(Expression.Not(expression.Body), expression.Parameters);
        }

        private static void Main()
        {
            // Match any string of length 2 or more characters
            Expression<Predicate<string>> expression = (s) => s.Length > 1;

            // Logical negation, i.e. match string of length 1 or fewer characters
            Expression<Predicate<string>> negatedExpression = ExpressionSample.Negate(expression);

            // Compile expressions to predicates
            Predicate<string> predicate = expression.Compile();
            Predicate<string> negativePredicate = negatedExpression.Compile();

            List<string> list1 = new List<string> { string.Empty, "an item", "x", "another item" };
            List<string> list2 = new List<string> { "yet another item", "still another item", "y", string.Empty };

            list2.RemoveAll(negativePredicate);
            list2.AddRange(list1.FindAll(predicate));

            list2.ForEach((s) => Console.WriteLine(s));
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文