Пример использования предиката для замены 'if' в c #?

Я читал, что ключевое слово «if» - зло, и лучше использовать предикат для замены if. Тогда я погуглил, но все равно не понял.

Кто-нибудь может быть добрым примером?

13.10.2009 06:13:13
Похоже, связано с этим вопросом: stackoverflow.com/questions/1554180/… (не дурак, просто контекст)
Greg Hewgill 13.10.2009 06:17:15
Это также может помочь - stackoverflow.com/questions/556425/predicate-delegates-in-c
Anand Shah 13.10.2009 06:26:28
Программа без ветвления действительно очень печальная.
Cecil Has a Name 13.10.2009 07:26:19
Программа без ветвления - вещь прекрасная. ;-)
Nick Hodges 9.02.2013 15:55:58
5 ОТВЕТОВ
РЕШЕНИЕ

Что бы ни говорили, если не зло. Могут быть конкретные случаи, для которых Предикат является лучшим выбором, чем if (или набор ifs).

Например,

 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));
9
13.10.2009 06:22:59

Я не использую их для прямых конструкций «если ... еще», кроме как внутри поиска, так как это также устраняет необходимость в конструкциях цикла. Например

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);

Я должен признать, однако, что если есть только прямое сравнение, чтобы выполнить на одном элементе, то я использую и конструкцию «если ... еще».

0
13.10.2009 06:23:14

Они просто разные. Предикат является более сложным, чем простое выражение if. Предикат - это, в основном, указатель на метод (делегат), который связан с типом, который он принимает в качестве параметра и возвращает истину / ложь.

Представьте, что вы используете дженерики и, подобно методу 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);
2
13.10.2009 07:13:59
Хороший ответ. Не знал немного о назначении делегатов на предикаты.
Bartek Tatkowski 13.10.2009 07:21:48
У вас все еще есть «зло, если» в первом примере :)
Groo 13.10.2009 07:24:24
У меня нет проблемы с «если», это служит цели
CRice 13.10.2009 23:38:28
@ Гру - Как вы предлагаете, чтобы мой метод поиска был написан без использования «если»?
CRice 13.10.2009 23:42:11

Например, когда у вас есть такой цикл:

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

Используя предикат, вы должны изменить его на:

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

Но я полагаю, что во всех дебатах «если заявление считается злым» , predicatevs ifтолько что упоминался как особый случай использования ООП и функционального программирования против процедурного программирования. Эта парадигма может быть легко обобщена для любого типа делегата (не только предиката) или любого использования ООП для замены условного:

Например, если вы просматриваете свой код, вы можете легко найти такой код:

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

Сторонники Pure OOP скажут вам, что вам нужно немедленно извлечь сотрудника другого типа и обработать каждую ветвь как отдельный подтип, что удалит «утверждение зла, если» :

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;
   }
}

Хотя код легче поддерживать таким образом, объем кода во втором случае явно удвоился. Для такой простой иерархии нет необходимости выполнять рефакторинг на этом этапе. Если вы решите, что вам нужно еще много особых случаев, то ваше условие может стать слишком сложным, и вы можете легко его рефакторизовать позже.

2
23.05.2017 12:24:45
    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"); }
0
20.12.2012 21:46:54