I have a following design in Java (7) application:
There is a method where i pass collection of objects of some type and object that I call "predicate" that is used to filter given collection.
Predicate is an interface with one method called test - it takes an object and return a boolean value.
In such situation:
Now I would like to have similar design in C# (4.0) application. I can see two way of doing it - by mimic Java design, or by change Predicate into delegate:
I can try to mimic Java design, but:
I can try achieve similar design using delegates. My filter method will take collection of object and Predicate delegate. In such case:
My question is - what in your opinion will be best way of achieve the same (or as similar as possible) design that I have in Java, that will be considered as correct, clean C#-approach of doing that?
I have few years of experience in programming in Java, but less that a year in C#, so I understand that maybe some problems that I see just doesn't exist in C# world or are not considered as problems at all.
EDIT: here is simplest (I think...) possible example of how my Java code work:
My "domain" object:
public class Person {
    private final String firstName;
    private final String secondName;
    public Person(String firstName, String secondName) {
        this.firstName = firstName;
        this.secondName = secondName;
    }
    public String getFirstName() {
        return firstName;
    }
    public String getSecondName() {
        return secondName;
    }
}
Filtering class:
public class Filter {
    public Collection<Person> filter(Collection<Person> collection, Predicate predicate) {
        Collection<Person> result = new LinkedList<Person>();
        for(Person person: collection) {
            if(predicate.test(person)) {
                result.add(person);
            }
        }
        return result;
    }
}
Predicate interface:
public interface Predicate {
    boolean test(Person person);
}
Two simple predefined implementations:
public class FirstNameStartsWithPredicate implements Predicate {
    private final String startsWith;
    public FirstNameStartsWithPredicate(String startsWith) {
        this.startsWith = startsWith;
    }
    public boolean test(Person person) {
        return person.getFirstName().startsWith(startsWith);
    }
}
public class LastNameEndsWithPredicate implements Predicate {
    private final String endsWith;
    public LastNameEndsWithPredicate(String endsWith) {
        this.endsWith = endsWith;
    }
    public boolean test(Person person) {
        return person.getSecondName().endsWith(endsWith);
    }
}
Utility class:
public final class PredicateUtils {
    public static Predicate and(final Predicate first, final Predicate second) {
        return new Predicate() {
            public boolean test(Person person) {
                return first.test(person) && second.test(person);
            }
        };
    }
    public static Predicate or(final Predicate first, final Predicate second) {
        return new Predicate() {
            public boolean test(Person person) {
                return first.test(person) || second.test(person);
            }
        };
    }
    public static Predicate allwaysTrue() {
        return new Predicate() {
            public boolean test(Person person) {
                return true;
            }
        };
    }
}
And finally, example of usage:
Collection<Person> persons = Arrays.asList(
        new Person("John", "Done"),
        new Person("Jane", "Done"),
        new Person("Adam", "Smith")
);
Filter filter = new Filter();
// Predefined predicates
filter.filter(persons, new FirstNameStartsWithPredicate("J"));
filter.filter(persons, new LastNameEndsWithPredicate("e"));
// anonymous implementation
filter.filter(persons, new Predicate() {
    public boolean test(Person person) {
        return person.getFirstName().equals("Adam") && person.getSecondName().equals("Smith");
    }
});
// utility class
filter.filter(persons, PredicateUtils.allwaysTrue());
filter.filter(persons, PredicateUtils.and(new FirstNameStartsWithPredicate("J"), new LastNameEndsWithPredicate("e")));
filter.filter(persons, PredicateUtils.or(new FirstNameStartsWithPredicate("J"), new FirstNameStartsWithPredicate("A")));
                This is totally doable in C#. Let's say we have a few users, and filters to filter them, some filters are built-in and some are implemented by users. Here we should use interfaces like Java instead of delegates.
public class User
{
    public string Name { get; set; }
    public int Age { get; set; }
    public string Address { get; set; }
}
public interface IPredicate<T>
{
    bool IsValid(T entity);
}
public class UserPredicate : IPredicate<User>
{
    /* built-in predicates */
    public static UserPredicate Adult = new UserPredicate(u => u.Age >= 18);
    public static UserPredicate NoAddress = new UserPredicate(u => string.IsNullOrEmpty(u.Address));
    public Func<User, bool> Predicate { get; private set; }
    public UserPredicate(Func<User, bool> predicate)
    {
        this.Predicate = predicate;
    }
    bool IPredicate<User>.IsValid(User entity)
    {
        return this.Predicate(entity);
    }
}
Users can easily add new predicates like this:
//user's code
var custom = new UserPredicate(MyCustomUserFilter);
bool MyCustomUserFilter(User u)
{
    //user's filter logic
}
It's not the same as Java, because in C# anonymous types can't implement an interface.
And also it's very easy to "combine" the predicates into a new one.
var AdultWithNoAddress = new UserPredicate(u => UserPredicate.Adult.Predicate(u) 
    && UserPredicate.NoAddress.Predicate(u));
EDIT To make the combination of predicates more clearer, you can put the combination logic into predicates itself.
public interface IPredicate<T>
{
    bool IsValid(T entity);
    IPredicate<T> And(IPredicate<T> another);
    IPredicate<T> Or(IPredicate<T> another);
}
public class UserPredicate : IPredicate<User>
{
    public static UserPredicate Adult = new UserPredicate(u => u.Age >= 18);
    public static UserPredicate NoAddress = new UserPredicate(u => string.IsNullOrEmpty(u.Address));
    private Func<User, bool> _predicate;
    public UserPredicate(Func<User, bool> predicate)
    {
        _predicate = predicate;
    }
    public bool IsValid(User entity)
    {
        return _predicate(entity);
    }
    public IPredicate<User> And(IPredicate<User> another)
    {
        return new UserPredicate(u => this.IsValid(u) && another.IsValid(u));
    }
    public IPredicate<User> Or(IPredicate<User> another)
    {
        return new UserPredicate(u => this.IsValid(u) || another.IsValid(u));
    }
}
//usage
var AdultWithNoAddress = UserPredicate.Adult.And(UserPredicate.NoAddress);
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With