C# how to pass 'any' function as a parameter to another function - c#

i have 5 datafunctions which all return the same type of object (List<source>)
Now i have to publish them in a WCF in which i have to surround the called code with all kind of error handling code (about 50 lines).
So i thought: because the code (51 lines) is all the same except the one line to get the data, just create one function with all the errorhandling a pass the function to get the data as a parameter to that function.
So i have these functions:
GetAllSources() : List<Source>
GetAllSourcesByTaskId(int taskId) : List<Source>
GetAllSourcesByTaskIdPersonId(int taskId, int personId) : List<Source>
GetAllSourcesByDate(DateTime startDate, DateTime endDate): List<Source>
and i want be able to pass them as a parameter to a function.
How should i declare the called function?
ps
i've read this one
how to pass any method as a parameter for another function
but it uses an Action object which can't return anything (as far as i understand) and i want to return a List

This should work:
List<Source> WithErrorHandling(Func<List<Source>> func)
{
...
var ret = func();
...
return ret;
}
Usage:
var taskId = 123;
var res = WithErrorHandling(() => { GetAllSourcesByTaskId(taskId); });

You can pass a Func which can take many input parameters are return a value:
Func<T1, T2, TResult>
In your case something like this could work:
public List<Source> GetList(Func<List<Source>> getListMethod) {
return getListMethod();
}
Then call using
GetList(() => GetAllSources());
GetList(() => GetAllSourcesByTaskIdPersonId(taskId, personId));

Could you not just pass the List as an argument into your method, might be a bit tidier?

Well, you didn't say anything about the code inside these functions, but if you use linq inside, than your approach is definitely not the best one.
You should use something like this:
IQueriable<SomeType> GetAllSources()
{
return (from source in sources select ...);
}
IQueriable<SomeType> GetAllSourcesByTaskId(int taskId)
{
return (GetAllSources()).Where(source => source.TaskId == taskId);
}

Related

Call F# function from C# passing function as a parameter

I have the following F# function
let Fetch logger id =
logger "string1" "string2"
// search a database with the id and return a result
In my C# class I want to call the Fetch F# function mocking out the logger function.
So I have the following C# function as the mocker.
void Print(string x, string y) { // do nothing }
I'm trying to call the F# function from a C# class with the following.
var _logger = FuncConvert.ToFSharpFunc<string, string>(Print);
var _result = Fetch(logger, 3);
The problem with FuncConvert.ToFSharpFunc is that takes only one type argument.
When I change the Fetch F# logger function to the following it works fine when I use ToFSharpFunc(Print) where the C# Print function also takes in one string.
let Fetch logger id =
logger "string1"
// search a database with the id and return a result
Anyone got ideas?
Short Version
var tupleLogger = FuncConvert.ToFSharpFunc<Tuple<string,string>>(t=>Print(t.Item1,t.Item2));
var logger = FuncConvert.FuncFromTupled(tupleLogger);
MyOtheProject.MyModule.Fetch(logger, 3);
Long Version
F# functions only accept one argument. Multiple arguments essentially create nested functions. You need to do the same on C#'s side.
Check the type of the logger parameter in C# with Intellisense. It's
Microsoft.FSharp.Core.FSharpFunc<string, Microsoft.FSharp.Core.FSharpFunc<string, a>>
FuncConvert.ToFSharpFunc can't create this. FuncFromTupled though can create this from an FSharpFunc that takes a Tuple with multiple fields as an argument.
That's something that can be created by ToFsharpFunc :
FSharpFunc<Tuple<string,string>,Unit> tupleLogger = FuncConvert.ToFSharpFunc<Tuple<string,string>>(
t=> Print(t.Item1,t.Item2));
or
var tupleLogger = FuncConvert.ToFSharpFunc<Tuple<string,string>>(t=> Print(t.Item1,t.Item2));
As FuncFromTupled's description says, it's A utility function to convert function values from tupled to curried form.. tupleLogger is a tupled form that we need to convert to a curried form:
var logger = FuncConvert.FuncFromTupled(tupleLogger);
The resulting code looks like:
var tupleLogger = FuncConvert.ToFSharpFunc<Tuple<string,string>>(t=>Print(t.Item1,t.Item2));
var logger = FuncConvert.FuncFromTupled(tupleLogger);
MyOtheProject.MyModule.Fetch(logger, 3);
You could create a utility function to combine the two conversions :
public static class MyFuncConvert
{
public static FSharpFunc<T1, FSharpFunc<T2, Unit>> ToFSharpFunc<T1, T2>(Action<T1, T2> action)
{
var tupled = FuncConvert.ToFSharpFunc<Tuple<T1, T2>>(
t => action(t.Item1, t.Item2));
var curried = FuncConvert.FuncFromTupled(tupled);
return curried;
}
}
Which would allow you to write :
var logger = MyFuncConvert.ToFSharpFunc<string,string>(Print);
F# functions can have only one argument. When you have for example: logger "string1" "string2" the expression logger "string1" creates another function with "string1" inside it which then can take "string2" as an argument. So to convert this you can create such helper method:
public static class FuncConvertExt
{
public static FSharpFunc<T1, FSharpFunc<T2, Unit>> Create<T1, T2>(Action<T1, T2> action)
{
Converter<T1, FSharpFunc<T2, Unit>> conv = value1 =>
{
return FuncConvert.ToFSharpFunc<T2>(value2 => action(value1, value2));
};
return FSharpFunc<T1, FSharpFunc<T2, Unit>>.FromConverter(conv);
}
}
Then you can do this:
var func = FuncConvertExt.Create<string, string>(Print);
func.Invoke("aaa").Invoke("bbb");
More info: https://blogs.msdn.microsoft.com/jaredpar/2010/07/27/converting-system-funct1-tn-to-fsharpfuncttresult/

Use Func<T,bool>[] as a parameter list and check the result for each function

UPDATED:
I am trying to write a method to do somes work and before it actually does those works it needs to go through some validations. Those validation varies based on what work it's going to do.
After some thoughts, I still want to use the same patterns with some minor changes.
Now, I want to make the following code works:
SomeClass:
public SomeResponse DoSomething<T>(params Func<T, bool>[] validations)
{
if(validations.All(v=>v(T))
{
some logic..
}
return SomeResponse;
}
Usage:
private Func<SomeRequest, bool> ValidateName = r =>
{return !string.IsNullOrWhiteSpace(r.Name);};
private Func<SomeRequest, bool> ValidatePhone = r =>
{return !string.IsNullOrWhiteSpace(r.Phone);};
var someResponse = SomeClass.DoSomething<SomeRequest>(ValidateName,ValidatePhone);
Again, the code currently doesn't work because it's giving me error on
if(validations.All(v=>v(T))
basically Type parameter is not valid here, and I couldn't find a way to pass in an actual SomeRequest object to the Func.
How should I write the code to loop through all the results return by the list of functions and make sure they are returning true, as well as keeping the flexibility of the Type parameter?
Answer:
Found a way to do that, hope this can be helpful:
Simply modify the method definition to :
SomeClass:
public SomeResponse DoSomething<T>(T request, params Func<T, bool>[] validations)
{
if(validations.All(v=>v(request))
{
some logic..
}
return SomeResponse;
}
Then use it like:
var someResponse = SomeClass.DoSomething<SomeRequest>(someRequest, ValidateName,ValidatePhone);
Please let me know if there is any other solution.
You're almost there!
First note that Validations is an array of Func<Request, bool> - that is, each item in the array is a function which takes a Request as a parameter and returns a bool.
So in order to get the bool out of the Func, you need to apply it to a Request object. In C#, applying a Func to an argument looks just like calling a method. So your LINQ expression will look like this:
validations.All(f => f(request))
This will return true if and only if all of the functions in validations return true (when applied to request).
So your full if block will look like this:
// I'm just guessing what the code to make a Request object will look like
Request request = resource.GetRequest();
if (!validations.All(f => f(request)))
{
throw new Exception("Not all of the validations checked out");
}
You haven't provided enough context for me to tell you where to get a Request object from but I'm sure you can figure it out.
Assuming I'm understanding these types correctly, I would think something like this should work:
if (Validations.All(v => v(resource)))
You don't need to use params here, a simple array will do. You can pass an arbitrary number of Func objects with an array.
public void DoSomething(Resource resource, Func<Request, bool>[] Validations)
Anyway, you can easily use LINQ's All method to check if all elements of an array satisfy a predicate.
if (Validations.All(v => v(resource)))

Need to inspect the values of a delegate method

I have a need to pass a delegate method with a varying number and type of parameters to another method. My hope is to be able to inspect the values of the parameters within the call.
This is my generic cache class.
public T Get<T>(Expression<Func<T>> getItemCallback) where T : class
{
T item = HttpRuntime.Cache.Get(hashRepresentationOfValues) as T;
if (item == null)
{
item = getItemCallback.Compile()();
HttpRuntime.Cache.Insert(
hashRepresentationOfValues,
item,
null,
DateTime.Now.AddMinutes(5),
TimeSpan.Zero);
}
return item;
}
My calls look like the following:
private DataContext db;
return cache.Get<List<SomeDBObject>>(
() => db.SomeDBObjectCall(param1, param2, param3));
As you can see it would be extremely helpful if I could dynamically determine the values of the delegate call as they could be used as the cache-key.
So basically, you have a method with an unknown signature that you want to wrap for caching purposes. If that's the case, you will definitely want to look into a technique called Memoization
Memoization on Wikipedia
In computing, memoization is an optimization technique used primarily to speed up computer programs by having function calls avoid repeating the calculation of results for previously processed inputs.
An example of such a function in C# would be something along these lines:
static Func<A, R> Memoize(this Func<A, R> f)
{
var dict = new Dictionary<A, R>();
return (A arg)=>
{
R result;
if (!dict.TryGetValue(arg, out result))
{
result = f(arg);
dict.Add(arg, result);
}
return result;
};
}
Note that the method takes a generic Func and returns a generic Func with the same signature. This way, you can effectively wrap your methods without bogging up the rest of your code. It is really seamless!
More examples here and here

C# - Generic type function is trying to assign result to System.Func(specified type) when a function with parameters is passed in

I'm using a class with a method that looks like the following:
public static T Get<T>(string key, Func<T> method)
{
//do stuff
var obj = method.Invoke();
return (T)obj
}
It works great if it I call it like this:
var x = Get<string>("mykey", test);
Where test is a function that has no parameters and returns a string. However, things break as soon as test has parameters. If I try:
var x = Get<string>("mykey", test(myparam));
I get the error "Argument type "String" is not assignable to parameter type "System.Func< string >".
I know the addition of (myparam) is the problem, but I'm not sure how it should be fixed. Is the issue with how the library's function is written or with how I'm trying to pass in the parameter?
var x = Get<string>("mykey", () => test(myparam));
You can call it like in the following sample code:
Get("mykey", () => test(myparam))
public static T Get<T>(string key, Func<T> method)
{
//do stuff
var obj = method.Invoke();
return (T)obj;
}
void Xyz()
{
int myparam = 0;
var x = Get("mykey", () => test(myparam)); // <string> is not needed
}
double test(int i)
{
return 0.0;
}
You need to curry the parameter by passing a lambda expression that takes no parameters and calls your function with a parameter from elsewhere:
var x = Get<string>("mykey", () => test(myparam));
It's how you're passing the parameter. test(myparam) has type String, and you need to pass a function which returns a String. You can make one with very little effort using a lambda expression:
var x = Get<string>("mykey", () => test(myparam));
The lambda expression () => foo creates a function which, when called, executes and returns foo.
You need to change your Func definition to define the input params thus:
Func<T,T1,T2,T3> method

Use more than one predicate in a function parameter?

I have a class that builds a url with query string parameters and so on. The class has a method: Url() which returns the complete url composed from the class properties and another method: UrlNew() which allows passing a predicate as parameter for the replacement of the value of one of the properties and THEN Returns the modified URL. Now, I need to modify this function to use TWO parameters, both predicates. How do I do that? I tried modifying the method's parameters as a List of predicates but I probably am not doing something right:
My OLD UrlNew() method looked like this:
public static string Url() (Action<LGUrlBuilder> predicate)
{
var instance = new LGUrlBuilder();
if (predicate != null) predicate(instance);
return instance.BuildUrl();
}
My NEW UrlNew() method looks like this:
public static string UrlNew(List<Action<LGUrlBuilder>> predicateList)
{
var instance = new LGUrlBuilder();
if (predicateList != null && predicateList.Count > 0)
{
foreach (Action<LGUrlBuilder> predicate in predicateList)
{
if (predicate != null) predicate(instance);
}
}
return instance.BuildUrl();
}
This compiles just fine but when I run it, using it in ASPX gives me this error:
CS1660: Cannot convert lambda expression to type 'System.Collections.Generic.List<System.Action<public_site.Library.LG.LGUrlBuilder>>' because it is not a delegate type
I am a C# beginner and I am sure I am doing something completely wrong. Any advice would help. Thanks!
Don't modify the function itself. Modify the method call like this:
UrlNew(x => { func1(x); func2(x); });
But if you really want to take arbitrary number of delegate instances as arguments, try modifying it like:
public static void UrlNew(params Action<LGUrlBuilder>[] list) {
// ... do what you're already doing in the second snippet ...
}
You can call it like:
UrlNew(x => firstthing(), x => secondthing(x), thirdthing);
Side note: An Action<T> is not called a predicate. A predicate returns a boolean value.
How about using the overloaded Action<T1,T2> delegate which accepts 2 parameters.
If you are looking to use a predicate instead which expects a boolean return value then use Func<T1,T2,bool> instead.

Categories

Resources