使用谓词替换“if”的示例在 c# 中?

发布于 2024-08-08 01:10:47 字数 75 浏览 8 评论 0原文

我读到“if”关键字是邪恶的,最好使用谓词来代替 if。然后我用谷歌搜索,但还是没有明白。

任何人都可以提供一个例子吗?

I read that the 'if' keyword is evil, and better to use predicate to replace if. Then I googled, but still dont get it.

Can anyone be kind to provide an example?

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

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

发布评论

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

评论(5

苍白女子 2024-08-15 01:10:47

不管他们说什么,如果不是邪恶的。在某些特定情况下,谓词可能是比 if(或一组 if)更好的选择。

例如,

 foreach (Foo f in fooList) {
     if (f.Equals(fooTarget)) {
        return f;
     }
 }

与(.NET 2.0)

 fooList.Find(delegate (Foo f) { return f.Equals(fooTarget); });

或(更高版本)

 fooList.Find(f => f.Equals(fooTarget));

No matter what they say, if is not evil. There may be specific cases for which a Predicate is a better choice than an if (or a set of ifs).

For example,

 foreach (Foo f in fooList) {
     if (f.Equals(fooTarget)) {
        return f;
     }
 }

versus (.NET 2.0)

 fooList.Find(delegate (Foo f) { return f.Equals(fooTarget); });

or (later)

 fooList.Find(f => f.Equals(fooTarget));
趴在窗边数星星i 2024-08-15 01:10:47

他们只是不同。谓词比简单的 if 语句更复杂。谓词基本上是指向方法(委托)的指针,该方法与作为参数并返回 true/false 的类型相关联。

想象一下,您正在使用泛型,就像泛型列表上的 find 方法一样,它如何在初始化列表之前知道列表中有哪些类型。所以find方法只是使用谓词,并不知道谓词将如何实现。

public T Find(Predicate<T> p)
    {
        //iterate through the collection and return the first match
        IEnumerator<T> enumerator = this.GetEnumerator();

        while (enumerator.MoveNext())
        {
            if (p(enumerator.Current))
            {
                return enumerator.Current;
            }
        }

        return default(T);
    }

在这种情况下,使用了谓词,但 (p(enumerator.Current)) 实际评估 enumerator.Current 的值是在谓词的实现期间确定的。代码不知道 T 最终会出现在这里。

这里有一些将谓词分配给方法的方法

Predicate<string> findShortNames1 = x => x.Length == 3; // lambda expression
Predicate<string> findShortNames2 = delegate(string x) { return x.Length == 3; }; // anonymous method
Predicate<string> findShortNames3 = MatchOnShortNames; //existing method

// ...
private bool MatchOnShortNames(string s)
{
    return s.Length == 3;
}

然后用法就像

someList.FindAll(findShortNames1);

They are just different. A predicate is more complex than a simple if statement. A predicate is basically a pointer to a method (delegate) which is tied to a type that it takes as a param and returns true/false.

Imagine you are using generics, and like the find method on generic lists, how can it know what types are in the list prior to your initialization of it. So the find method just uses the predicate and does not know how the predicate will be implemented.

public T Find(Predicate<T> p)
    {
        //iterate through the collection and return the first match
        IEnumerator<T> enumerator = this.GetEnumerator();

        while (enumerator.MoveNext())
        {
            if (p(enumerator.Current))
            {
                return enumerator.Current;
            }
        }

        return default(T);
    }

In this case, a predicate is used but what (p(enumerator.Current)) actually evaluates about enumerator.Current is determined during implementation of the predicate. The code is not aware of what type T wil end up being here.

Here are some ways to assign the predicate to a method

Predicate<string> findShortNames1 = x => x.Length == 3; // lambda expression
Predicate<string> findShortNames2 = delegate(string x) { return x.Length == 3; }; // anonymous method
Predicate<string> findShortNames3 = MatchOnShortNames; //existing method

// ...
private bool MatchOnShortNames(string s)
{
    return s.Length == 3;
}

Then the usage is like

someList.FindAll(findShortNames1);
暖树树初阳… 2024-08-15 01:10:47

例如,每当你有这样的循环:

List<Employee> retiredEmployees = new List<Employee>();
foreach (Employee employee in EmployeeList)
{
    if (employee.IsRetired)
        retiredEmployees.Add(employee);
}

使用谓词时,你就必须将其更改为:

retiredEmployees = EmployeeList.FindAll(e => e.IsRetired);

但我相信,总的来说 “if 语句被认为是邪恶的” 辩论,predicateif 只是作为使用的一种特殊情况而提到OOP 和函数式编程与过程式编程。这个范例可以很容易地推广到任何委托类型(不仅仅是谓词),或者任何使用 OOP 来替换条件的情况:

例如,如果你浏览你的代码,你可能很容易找到这样的代码:

public class Employee
{
    private bool _isRetired;
    private double _amount;
    public double GetPayAmount()
    {
         if (_isRetired)
            return _amount * 0.9;
         else
            return _amount;
    }
}

纯 OOP 支持者会告诉你您立即需要提取不同类型的员工并将每个分支作为不同的子类型处理,这将删除“邪恶的 if 语句”

public interface IEmployee
{
   double GetPayAmount();
}

public class Employee : IEmployee
{
   private double _amount;
   public double GetPayAmount()
   {
       return _amount;
   }
}

public class RetiredEmployee : IEmployee
{
   private double _amount;
   public double GetPayAmount()
   {
       return _amount * 0.9;
   }
}

虽然这种方式代码更容易维护,但数量第二种情况下的代码明显增加了一倍。对于这样一个简单的层次结构,在此阶段几乎不需要进行重构。如果您决定需要更多特殊情况,那么您的条件可能会变得太复杂,并且您可以稍后轻松重构它。

For example, whenever you have a loop like this:

List<Employee> retiredEmployees = new List<Employee>();
foreach (Employee employee in EmployeeList)
{
    if (employee.IsRetired)
        retiredEmployees.Add(employee);
}

Using a predicate, you would have to change it to:

retiredEmployees = EmployeeList.FindAll(e => e.IsRetired);

But I believe, in the whole "if statement considered evil" debate, predicate vs if is just mentioned as a special case of using OOP and functional programming vs procedural programming. This paradigm can be easily generalized to any delegate type (not just predicate), or any use of OOP to replace a conditional:

For example, if you go through your code, you may easily find code such as this:

public class Employee
{
    private bool _isRetired;
    private double _amount;
    public double GetPayAmount()
    {
         if (_isRetired)
            return _amount * 0.9;
         else
            return _amount;
    }
}

Pure OOP supporters will tell you that you immediately need to extract a different type of employee and handle each branch as a different subtype, which will remove the "evil if statement":

public interface IEmployee
{
   double GetPayAmount();
}

public class Employee : IEmployee
{
   private double _amount;
   public double GetPayAmount()
   {
       return _amount;
   }
}

public class RetiredEmployee : IEmployee
{
   private double _amount;
   public double GetPayAmount()
   {
       return _amount * 0.9;
   }
}

Although the code is easier to maintain this way, the amount of code in the second case has clearly doubled. For a simple hierarchy as this, there is little need to do the refactoring at this phase. If you decide that you need many more special cases, then your conditional might become too complex, and you can easily refactor it later.

溺ぐ爱和你が 2024-08-15 01:10:47

除了内部搜索之外,我自己不会将它们用于直接的“if ... else”构造,因为它也消除了对循环构造的需要。例如

int index = this.listObjects.FindIndex(x => x.PropertyA == objectItem.PropertyA);

,或者

List<ClassA> listClass = new List<ClassA>();

//... some more code filling listClass with ClassA types ...

ClassA tempClassA = listClass.FirstOrDefault().Where(x=> x.PropertyA == someValue);

我必须承认,如果只是对一项进行直接比较,那么我会使用“if ... else”结构。

I don't use them for straight "if ... else" constructs myself, other than withinn searches, as it also removes the need for loop constructs. For example

int index = this.listObjects.FindIndex(x => x.PropertyA == objectItem.PropertyA);

or

List<ClassA> listClass = new List<ClassA>();

//... some more code filling listClass with ClassA types ...

ClassA tempClassA = listClass.FirstOrDefault().Where(x=> x.PropertyA == someValue);

I must admit though that if there's just a straight comparison to perform on one item then I use and "if ... else" construct.

洛阳烟雨空心柳 2024-08-15 01:10:47
    static void Main()
    {
        string[] names = { "Lukasz", "Darek", "Milosz" };

        foreach (var item in names)
        {
            if (ContainsL(item))
                 Console.WriteLine(item);
        }

        string match1 = Array.Find(names, delegate(string name) { return name.Contains("L"); });
        //or
        string match2 = Array.Find(names, delegate(string name) { return name.Contains("L"); });
        //or
        string match3 = Array.Find(names, x => x.Contains("L"));


        Console.WriteLine(match1 + " " + match2 + " " + match3);     // Lukasz Lukasz Lukasz
    }
    static bool ContainsL(string name) { return name.Contains("L"); }
    static void Main()
    {
        string[] names = { "Lukasz", "Darek", "Milosz" };

        foreach (var item in names)
        {
            if (ContainsL(item))
                 Console.WriteLine(item);
        }

        string match1 = Array.Find(names, delegate(string name) { return name.Contains("L"); });
        //or
        string match2 = Array.Find(names, delegate(string name) { return name.Contains("L"); });
        //or
        string match3 = Array.Find(names, x => x.Contains("L"));


        Console.WriteLine(match1 + " " + match2 + " " + match3);     // Lukasz Lukasz Lukasz
    }
    static bool ContainsL(string name) { return name.Contains("L"); }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文