user2334626
user2334626

Reputation: 197

Passing a function to another function

I am writing an HTTP wrapper class object in C# and I would like to give the main method the ability to receive a function as a parameter and then execute it on the source HTML returned by the POST/GET.

For example I may want to pass a function that checks the headers for a cookie and only returns true if it's found OR pass a regular expression function that checks the source for a piece of content.

I know in PHP or JS I could easily just pass functions as parameters but I am not sure on how to go about it without creating delegates that match the functions I want to use.

I would like the code to be as "generic" as possible so that it could receive any function e.g Pseudocode would be like

public bool MakeHTTPRequest(string url, object possiblefunction)
{

   make HTTP request

   if status == 200
   {

    string response = getresponse

    if(object is function){

        call object
    }
  }
}

So the function may OR may NOT be passed in, or I may set a global property with it. Then I need to check IF a function exists and execute it if it does.

The function could be ANYTHING and I want to future proof the code so it can handle any kind of function in the future that maybe passed to it.

Any help would be much appreciated.

Thanks

Upvotes: 0

Views: 1670

Answers (2)

Colin Smith
Colin Smith

Reputation: 12540

Use either Func or Action (or Predicate as mentioned by DavidN) to specify the contract of delegates passed as a parameter into your MakeHTTPRequest method.

public bool MakeHTTPRequest(string url, Action possiblefunction)
{

   make HTTP request

   if status == 200
   {

    string response = getresponse

    if(possiblefunction != null){

        possiblefunction();
    }
  }
}

If your "function" returns a value/result then use Func instead..(where T is the expected return type)...e.g. Func<int>.

If your "function" expects parameters then specify the expected parameter types. So here are some examples:

Func<string,float,int> - a delegate which expects string and float parameters and returns an int result

Action - a delegate that takes no parameters, and doesn't return a value

Action<string,float> - a delegate that doesn't return a value (void), and expects a string and float as parameters.

If you're trying to pass back the "response" to the possiblefunction then do something like this.

public bool MakeHTTPRequest(string url, Action<string> possiblefunction)
{

   make HTTP request

   if status == 200
   {

    string response = getresponse

    if(possiblefunction != null){

        possiblefunction(response);
    }
  }
}

Upvotes: 1

DavidN
DavidN

Reputation: 5197

Based on the examples you've given, it seems that what you really want is to pass in a set of validators to determine if the HTTP response meets certain criteria. This seems to be further corroborated by the fact that your method is returning bool.

A Predicate<T>, or actually a set of Predicates, should encapsulate criteria rules that you pass in to determine whether the request is valid or not.

The signature for a Predicate<T> is bool Predicate<T>(T t) - meaning that it takes in some type and produces a bool

Using an array of predicates, and making sure they all pass, seems to be a pretty future-proof way for what you want to do

public bool MakeHTTPRequest(string url, params Predicate<WebResponse>[] validators)
{    
   // make HTTP requrest

   var request = HttpWebRequest.Create(url);
   var response = (HttpWebResponse)request.GetResponse();

   if (response.StatusCode == HttpStatusCode.OK){
        foreach(var validator in validators)
            if (!validator(response))
                return false;
   }

    return true;    
}

The trick is that the params keyword allows you to call the method passing in [0..any number] of values for the params, so all of the following invocations would work:

MakeHTTPRequest("http://stackoverflow.com");
MakeHTTPRequest("http://stackoverflow.com", r => r.Headers.AllKeys.Contains("CookieHeader"));
MakeHTTPRequest("http://stackoverflow.com", r => r.Headers.AllKeys.Contains("CookieHeader"), r => r.ContentLength < 10000);

Upvotes: 0

Related Questions