как написать функцию предиката - PullRequest
0 голосов
/ 31 октября 2018

У меня есть такой класс:

    public class A
    {
        public string Username { get; set; }
        public bool IsOK { get; set}
    }

    public class B:A
    {
        public string test { get; set; }
    }
    public class C:B
    {
        public string test2 { get; set; }
    }

В моем основном классе:

    static void main()
    {
        var a = new B() { Username = "User1", IsOK = false };
        var b = new B() { Username = "user2", IsOK = false };
        var c = new C() { Username = "admin", IsOK = true };
        List<B> bclasses = new List<B>() { a, b, c };
        // I want to filter out username is user2 or IsOK is true
        var username = "user2";
        var select = bclasses.Where(b => b.IsOK || b.Username == username).ToList();
    }

Но я не хочу каждый раз писать код "b => b.IsOk || b.UserName == username". Как я могу написать предикат внутри Где это так, чтобы оно было кратким? Спасибо.

Ответы [ 3 ]

0 голосов
/ 31 октября 2018

Вам нужна функция, которая принимает B или C и возвращает логическое значение, указывающее, включать ли его в ваш список. Другими словами, Func<B,bool>. Вы можете определить это так:

Func<B,bool> predicate = x => x.IsOK || x.Username == username;

И чтобы использовать его, просто передайте его Where.

var selection = bclasses.Where( predicate ).ToList();
0 голосов
/ 31 октября 2018

Вы можете объявить предикат как Func<A, bool>:

Func<A, bool> predicate = x => x.IsOK || x.Username == username;

Или вы можете объявить его как локальную функцию:

bool predicate(A x) => x.IsOK || x.Username == username;

(К сожалению, вы не можете использовать Predicate<A>, потому что это не тот тип, который принят IEnumerable.Where().)

В любом случае, если он определен внутри метода, он может захватить локальный username и, следовательно, для него не требуется параметр.

Вот исправленный и компилируемый пример:

using System.Collections.Generic;
using System.Linq;

namespace Demo
{
    public class A
    {
        public string Username { get; set; }
        public bool   IsOK     { get; set; }
    }

    public class B: A
    {
        public string test { get; set; }
    }

    public class C: B
    {
        public string test2 { get; set; }
    }

    static class Program
    {
        public static void Main()
        {
            var     a        = new B() { Username = "User1", IsOK = false };
            var     b        = new B() { Username = "user2", IsOK = false };
            var     c        = new C() { Username = "admin", IsOK = true };
            List<B> bclasses = new List<B>() { a, b, c };

            // I want to filter out username is user2 or IsOK is true
            var username = "user2";

            bool predicate(A x) => x.IsOK || x.Username == username; // <=== Here is the predicate.

            var select = bclasses.Where(predicate).ToList();
        }
    }
}

Теперь, предположив, что вы на самом деле хотите передать аргумент username предикату вместо его захвата, вы можете просто добавить параметр в предикат следующим образом:

bool predicate(A x, string name) => x.IsOK || x.Username == name;

И тогда вы передадите username предикату внутри Where() следующим образом:

var select = bclasses.Where(item => predicate(item, username)).ToList();
0 голосов
/ 31 октября 2018

В этом случае, я думаю, вам может понадобиться реализовать функцию (Func), а не предикат.

Спасибо @Fildor за указание мне неиспользованного делегата, чтобы я инкапсулировал его в нечто вроде этого:

 Func<List<A>, string, List<A>> selectValidUser = (users, filterName) =>
 {
    return users.Where(u => u.IsOK || u.Username == filterName).ToList();
 };

 var selectedUsers = selectValidUser(bclasses, username);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...