It's dangerous to code alone! Take this.

The Sieve

The following is one possible solution to this challenge.

Console.Write("Which filter do you want to use? (1=Even, 2=Positive, 3=MultipleOfTen) ");
int choice = Convert.ToInt32(Console.ReadLine());

Sieve sieve = choice switch
    1 => new Sieve(IsEven),
    2 => new Sieve(IsPositive),
    3 => new Sieve(IsMultipleOfTen)

while (true)
    Console.Write("Enter a number: ");
    int number = Convert.ToInt32(Console.ReadLine());

    string goodOrEvil = sieve.IsGood(number) ? "good" : "evil";
    Console.WriteLine($"That number is {goodOrEvil}.");

bool IsEven(int number) => number % 2 == 0;
bool IsPositive(int number) => number > 0;
bool IsMultipleOfTen(int number) => number % 10 == 0;

public class Sieve
    private Func<int, bool> _decisionFunction;

    public Sieve(Func<int, bool> decisionFunction) => _decisionFunction = decisionFunction;

    public bool IsGood(int number)
        return _decisionFunction(number);

Answer this question: Describe how you could have also solved this problem with inheritance and polymorphism. Which solution seems more straightforward to you, and why?

Instead of passing methods by name to the Sieve class, you could have made a Sieve base class and then different implementations for each. Maybe something like this:

public abstract class Sieve
    public abstract bool IsGood(int number);

public class EvenSieve : Sieve
    public override bool IsGood(int number) => number % 2 == 0;

public class PositiveSieve : Sieve
    public override bool IsGood(int number) => number > 0;

public class MultipleOfTenSieve : Sieve
    public override bool IsGood(int number) => number % 10 == 0;

You could also make Sieve be an interface instead of a class, and then just have the three above specialized classes just implement the interface.

This solution is workable. There isn’t anything horribly wrong with it, and I think there’s a time and a place for such solutions, as well as a delegate-based solution.

Personally, I think this particular problem works better with delegates instead of inheritance. The original solution, above, has three total lines for the different methods used in the delegates. The inheritance/polymorphism version uses nine total lines (not including blank lines), and it sort of hides the meat of the code more. So my opinion is that the delegate version is better in this specific case.