Passing a function to another function - c#

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

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.
http://www.blackwasp.co.uk/FuncAction.aspx
Func vs. Action vs. Predicate
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);
}
}
}

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);

Related

Unit Test the a string that is used to pass to another function using XUnit and NSubstitute in ASP.NET Core

So I have a function like this that will call other function and pass in a string that will be returned based on different condition. They will always use a normal string, however if certain conditions are met then the special string will be used to passed in to the other function instead.
public async Task Func(context)
{
var stringToBeUsed = GetNormalString(context);
if (FirstConditionFulfilled(context) &&
(SecondConditionFulfilled(context))
{
stringToBeUsed = GetSpecialString(context);
}
await DoSthElse(context, stringToBeUsed );
}
This is the get normal string function
private string GetNormalString(context)
=> context.HttpContext.DoSthToGetNormalString().ToString();
And this is the get special string function
private string GetSpecialString(context)
=> context.HttpContext.DoSthToGetSpecialString().ToString;
I wonder how should I set up the unit test to see if certain conditions are met, the stringToBeUsed will be the special string, otherwise, will be the normal string?
Your Function does two things:
get the special string and then
do something with it.
That makes it hard to test. Why dont you put the getting of the string in a new function and now each function only does one thing that you can test easier:
public string GetTheRightString(context){ //new function you can easily test
var stringToBeUsed = GetNormalString(context);
if (FirstConditionFulfilled(context) &&
(SecondConditionFulfilled(context))
{
stringToBeUsed = GetSpecialString(context);
}
return stringTobeUsed;
}
public async Task Func(context)
{
var stringToBeUsed = GetTheRightString(context);
await DoSthElse(context, stringToBeUsed );
}
But you probably dont want to make that method public. If you keep it private and you want to test it (which is a topic some people are very dogmatic about that you should never do that. I disagree) look here. Or you put the method in a new class and make that public/internal. There is no right or wrong here in my opinion.

How to do 'out' in a Func<T> in c#

I am using a library which measure metrics for running code.
The usage of the library is something like this.
_Library.Wrap("AnyStringForMetrics", Func<T>);
So whatever I pass into the Func as a lambda will be measured and result of it will be returned.
At the moment, I have method where I want to measure this line where it tries to create or get a user with that id. (newlyCreated will be true if the user was created)
public User GetOrCreate(long id, out bool newlyCreated) {
// some random checks
return UserDatabase.GetOrCreate(id, out newlyCreated);
}
But now, if I try to wrap my code around
public User GetOrCreate(long id, out bool newlyCreated) {
// some random checks
return _Library.Wrap(
"UserGetOrCreate", () => UserDatabase.GetOrCreate(id, out newlyCreated));
}
I will get an exception for using "out" inside lambda expression. How should I resolve this?
If possible please write out a concrete code example... Thanks.
Use a ValueTuple as return type instead and thus avoid using an out parameter.
public (User user, bool newlyCreated) GetOrCreate(long id) {
var user = ....;
bool created = ....;
return (user, created);
}
and map it to Func<(User, bool)>.

Null OR generic as parameter method

In Java you can do this:
protected void makeRequest<T extends BaseJsonClass, T2 extends BaseJsonClass> (Response<T> response, T2 dataToSend, String url) {}
Some request:
makeRequest(response, null, serverUrl);
makeRequest(response, jsonData, serverUrl);
In C# how?
I'm writing a method that should be able to accept data as null or as a specific type of object.
/**
* Make a request to the server.
* dataToSend can be null.
* */
protected void makeRequest<T, T2>(Response<T> response, T2 dataToSend, string url) where T : JsonObjectBase where T2 : JsonObjectBase
{ }
Currently I'm getting the problem:
The type arguments for method `BaseModelController.makeRequest<T,T2>(Response<T>, T2, string)'
cannot be inferred from the usage. Try specifying the type arguments explicitly
How would I allow a generic that can possibly be null as well?
** EDIT 1 **
I invoke this method like so:
makeRequest(response, null, serverUrl);
or
makeRequest(response, someJsonData, serverUrl);
** EDIT 2 **
JsonObjectBase is just an object that is extended by other Json classes so I can parse/serialize them auto-magically knowing that it will always be a Json object. I use it for type checking so other coders don't make the mistake of entering an unknown object.
Passing null is really much better than defining the same value which is 'suppose' to not do anything; because that gets messy very fast.
Example of the power
ModelControllerAccount.getInstance().createUser(
username.text, password.text, // Params
new Response<JsonUserAccountFeedback>(
success: (jsonObjectStandardResponse) => Debug.Log("Success when creating account. Data: " + jsonObjectStandardResponse.getAccessToken()),
failed: (failedReason) => Debug.Log("Failed to make request. Reason: " + failedReason.getReasonDescription())
)
);
If you can change the API somewhat, one easy way to fix this would be to add an overload that omits the second parameter. This is easier for the caller too in cases where you're not sending any data.
Like this:
protected void makeRequest<T>(Response<T> response, string url) where T : JsonObjectBase
{
makeRequest (response, default(JsonObjectBase), url);
}
Since you're most likely only need access to the methods of JsonObjectBase you could do something like this:
protected void MakeRequest<T>(Response<T> response, JsonObjectBase dataToSend, string url) where T : JsonObjectBase
{
}
and call the method like this: MakeRequest(response, null, serverUrl);
Or you could even take advantage of optional arguments:
protected void MakeRequest<T>(Response<T> response, string url, JsonObjectBase dataToSend = null) where T : JsonObjectBase
{
}
and call the method like this: MakeRequest(response, serverUrl);
This happens because a value of null doesn't tell the compiler the type of that parameter. After all, the implementation of makeRequest could check the type of T2 and do wildly different things depending on what it sees. If you had passed, say, a variable with the type of List<int>, it would know that T2 is List<int>, but null could be the value of any reference type. If the compiler can't figure out the type (or if it ever decides the wrong one), you'll need to tell it:
Response<string> myResponse;
makeRequest<Response<string>, object>(myResponse, null, "http://example.com");
I've just specified the types used to call the generic method. In this case, the type of the null parameter is object.

how to convert Expression<Action> to Action

Hey i was wondering if i can convert an Expression to an Action.
I need to use the Expression to get the details of the lambda expression and at the same time i need to execute it using a different method. I need to get the Expression and the actual action with just using a single parameter (either Action or Expression):
BTW i need this for Getting details on what kind of assert i did. ex(Assert.true, Assert.False)
public void otherMethod()
{
SomeMethod(() => Assert.Equals("Dog","Cat"));
}
public void SomeMethod(Expression<Action> neededAction) //or public void SomeMethod(Action neededAction)
{
//i need to run the neededAction and get the details whether what assert i did and the inputs i used for the assertion
}
So basically i need to run the Action and i need to get its method infos.
Thanks~
You need to call Compile() on the expression.
// Compile it.
var actualNeededAction = neededAction.Compile();
// Execute it.
actualNeededAction();

C# Generics and using the non-generic version from typed method

I'm using the RestSharp library to access a REST API.
I want all the API requests to go through the same method, so I can add headers, handle errors and do other stuff in a central place.
So I made a method that accepts a generic Func<> and that solves most of my problems, but I don't know how to handle the case where I don't have a return type.
private T PerformApiCall<T>(RestRequest restRequest, Func<RestRequest, IRestResponse<T>> restMethod)
{
var response = restMethod.Invoke(restRequest);
//handle errors
....
return response.Data;
}
I call it like this:
var apples = PerformApiCall(new RestRequest('/api/apples'), req => Client.Execute<List<Apple>>(req));
But I came across a problem, a bunch of API calls don't have a return type because they don't return data. So I used Client.Execute(req) and I get the error saying the type arguments cannot be inferred, I tried to pass , but that failed because it couldn't convert the non-generic IRestResponse to the typed one.
Any ideas on how to tackle this in a nice way?
One thing you could try is to add an overload to your PerformApiCall function that takes a Func with a non-generic result type, and returns nothing:
// Notice the `Func` has `IRestResponse`, not `IRestResponse<T>`
public void PerformApiCall(RestRequest restRequest,
Func<RestRequest, IRestResponse> restMethod)
...
Then, depending on how complex your error checking/logic is, you could move it out to a separate method (which returns the response), and call it from both overloads of PerformApiCall:
private T PerformRequestWithChecks<T>(RestRequest restRequest,
Func<RestRequest, T> restMethod)
where T : IRestResponse
{
var response = restMethod.Invoke(restRequest);
// Handle errors...
return response;
}
// You can use it from both versions of `PerformApiCall` like so:
//
// // From non-generic version
// var response =
// PerformRequestWithChecks<IRestResponse>(restRequest, restMethod);
//
// // From generic version
// var response =
// PerformRequestWithChecks<IRestResponse<T>>(restRequest, restMethod);
// return response.Data;
You were getting a compiler error because it is sound to treat a subtype as if it was an instance of its supertype, but it is not sound to do it in the other direction (which is what was happening when you changed your calling code to just Client.Execute(req), returning a non-generic).
Here's an ideone paste illustrating this: http://ideone.com/T2mQfl

Categories

Resources