Search code examples
c#functional-programmingdelegatespredicate

A generic predicate which can be customized by caller?


I have a bunch of Predicates defined like this, each checking for a different http status code:

readonly Predicate<HttpResponseData> createdHttpStatusPredicate = (HttpResponseData responseData) => {
    return responseData.StatusCode == HttpStatusCode.Created;
};

readonly Predicate<HttpResponseData> okHttpStatusPredicate = (HttpResponseData responseData) => {
    return responseData.StatusCode == HttpStatusCode.OK;
};

...

I'm passing them into the following method like this (code has been simplified a little to cut out irrelevant details):

public static async Task<HttpResponseData> HttpCaller(HttpMethod requestMethod, Predicate<HttpResponseData> predicate)
{
    HttpResponseData response = await SendHttpRequest(requestMethod);

    if (predicate(response) == true)
        return response;
    else
        return null;
}

Here is a sample call sending one predicate into above method:

HttpResponseData data = await HttpRequestUtils.HttpCaller(HttpMethod.Post, createdHttpStatusPredicate);

I'm wondering, can I combine all the predicates in some generic predicate, or perhaps somehow specify the http status to look for into the predicate when I'm calling HttpCaller ?

Yes, I know the above example doesn't make much sense as I can just pass the http status I'm looking for into HttpCaller directly without going through a predicate, but in my case HttpCaller can receive my complex predicates as inputs too, based on where HttpCaller is being called from


Solution

  • The next two approaches can be used to get rid of all the predicates that only check for HttpStatusCode.


    1. Create a method that creates a Predicate for a given HttpStatusCode:

    public static Predicate<HttpResponseData> CreatePredicateByHttpStatusCode(HttpStatusCode status)
    {
        return r => r.StatusCode == status;
    }
    

    And then use this method when you need a Predicate that only checks for a given HttpStatusCode:

    var result = await HttpCaller(httpMethod, CreatePredicateByHttpStatusCode(HttpStatusCode.OK));
    

    2. Create an overload of the method HttpCaller that accepts HttpStatusCode and only checks for a given HttpStatusCode:

    // This is your current method. It accepts a common Predicate that is used
    // to check for complex conditions.
    public static async Task<HttpResponseData> HttpCaller(HttpMethod requestMethod, Predicate<HttpResponseData> predicate)
    {
        HttpResponseData response = await SendHttpRequest(requestMethod);
    
        if (predicate(response) == true)
            return response;
        else
            return null;
    }
    
    // This is a new Method. It accepts HttpStatusCode instead of the Predicate.
    // It can be used for checking only for HttpStatusCode.
    public static async Task<HttpResponseData> HttpCaller(HttpMethod requestMethod, HttpStatusCode status)
    {
        // Here your original method HttpCaller is used.
        return await HttpCaller(requestMethod, r => r.StatusCode == status);
    }
    

    Overloaded form of the HttpCaller can be used when you need to check only for HttpStatusCode:

    var result = await HttpCaller(httpMethod, HttpStatusCode.OK);