Creating a generic filter system to pass into an API request I am building an application that will interact with an API.
My service layer will call the repository which will request data from the API.
I want to be able to pass filters to the repository and came up with the following. I am just curious if there are better ways of doing this?

First, I created an interface called IFilter:

public interface IFilter
{
    string GetFilterName();
    string GetFilterValue();
}


I then have a bunch of filters, for example:

public class CreatedAfterFilter : IFilter
{
    readonly string _name = "CreatedAfter";
    DateTime _value;

    public CreatedAfterFilter(DateTime value)
    {
        this._value = value;
    }

    public string GetFilterValue()
    {
        return _value.ToString("yyyy-MM-ddTHH:mm:ss+00:00");
    }

    public string GetFilterName()
    {
        return _name; ;
    }
}


...or

public class OrdersFilter : IFilter
{
    readonly string _name = "OrderIdList";
    List&lt;Order&gt; _value;

    public OrdersFilter(List&lt;Order&gt; value)
    {
        this._value = value;
    }

    public string GetFilterValue()
    {
        return '[' + String.Join(",", _value.Select(x =&gt; x.OrderId)) + ']';
    }

    public string GetFilterName()
    {
        return _name; ;
    }
}


When I call my repository, I do something like this:

var filters = new List&lt;IFilter&gt;();
filters.Add(new CreatedAfterFilter(DateTime.UtcNow.AddDays(-110)));
filters.Add(new OrderFilter(1709359));            
var orders = orderRepository.GetSingleOrder(filters);


Then in my code that calls the API, I do this to create the query string:

foreach (var filter in filters)
{
   getParams.Add(new KeyValuePair&lt;string, string&gt;(filter.GetFilterName(), filter.GetFilterValue()));
}


Am I on the right track here?
This is my first real time in writing C# an using Interfaces.
Am I on the right track here?


I think you are. Here's how you can use a few tricks to make it even shorter.



Instead of the interface you can implement what is common in an abstract class.

public abstract class Filter
{
    public virtual string Name =&gt; Regex.Replace(GetType().Name, $"{nameof(Filter)}$", string.Empty);
    public static implicit operator string(Filter filter) =&gt; filter.ToString();
}


This means the base class will get the name of the filter from its type and it'll be able to implicitly cast it into a string by calling ToString. Now everything the derived class needs to do is to implement its own ToString:

public class CreatedAfterFilter : Filter
{
    private DateTime _value;

    public CreatedAfterFilter(DateTime value)
    {
        _value = value;
    }

    public override string ToString()
    {
        return _value.ToString("yyyy-MM-ddTHH:mm:ss+00:00");
    }    
}


So later in the loop you can just do this:

foreach (var filter in filters)
{
   getParams.Add(new KeyValuePair&lt;string, string&gt;(filter.Name, filter));
}




If you make the Name property virtual you can override it in a derived class if the name of the filter cannot be derived from its type name:

public class OrdersFilter : Filter
{
    public override string Name =&gt; "OrderIdList";

    public override string ToString()
    {
        ...
    }
}