Function like bool decide(bool x) can be passed in method as parameter as functor as:
foo(Func<bool,bool> lambda)
We can have lambda expression like ()=>{int x=8; x=x+2;} that does not take anything and return anything. Lets say I want to pass such function as parameter to another method bar then how can it be done?
This is Action, not Func. If you don't want to return value, then you must use Action.
For example:
Action<int> example1 = (int x) => Console.WriteLine("Write {0}", x);
example1.Invoke(1); // or example1(1);
Action example3 = () => Console.WriteLine("Done");
example3.Invoke(); // or example3();
You'll want an Action!
Presumably it'll do more work than set and manipulate a local variable, though?
Related
I want to write a function that takes a function as an argument and then do different things based on whether the passed-in function returns void vs a value.
C# signature checking can't tell the difference so I'm stuck doing it in code.
Is there an easy way to test whether an arbitrary function returns void?
To be clear. I explicitly am not interested in a compile error. I just want the equivalent of what I can do for any other object.
void IsString(object o) => o is string;
void ElseWhere() {
object o = 1;
if (IsString(o)) Bla();
However even this gets a compile error claiming the two methods are ambiguous. It doesn't flag the methods themselves ambiguous but I get an error on the call saying it can't resolve between them.
private static bool HasNoReturnValue(Action o) => true;
private static bool HasNoReturnValue(Func<object> o) => false;
...
if (HasNoReturnValue(SomeFunction)) Bla();
As do anything I've tried involving typeof:
if (SomeFunction is typeof(Func(object>)) Bla();
Let's say you have two methods, one of which returns a Boolean and one which returns void.
void SomeFunction1()
{
}
bool SomeFunction2()
{
return false;
}
To pass either of these as a pointer to a method, you have to convert them to a delegate. Two types of delegates: Action and Func<bool>, respectively:
var action1 = new Action(SomeFunction1);
var action2 = new Func<bool>(SomeFunction2);
You can then write two methods that accept these types as arguments:
void AcceptDelegate(Action action)
{
Console.WriteLine("The delegate returns void.");
}
void AcceptDelegate(Func<bool> func)
{
Console.WriteLine("The delegate returns a Boolean.");
}
And call them like this:
AcceptDelegate(action1);
AcceptDelegate(action2);
Or you could pass the method group directly and the compiler will figure out the type (Why? See the Microsoft documentation on c# method group conversions):
AcceptDelegate(SomeFunction1);
AcceptDelegate(SomeFunction2);
Either way you call them, you would get this output:
The delegate returns void.
The delegate returns a Boolean.
The reason this works is the compiler will automatically pick the right one at compile-time, based on the type of the delegate, just as it would pick the overload for any type such as string or integer. This is the type-safe / early-bound way to do it.
If you insist on an "any delegate"/ late binding sort of approach, you could do something like this:
void AcceptAnyDelegate(Delegate anyAction)
{
Console.WriteLine("The function returns a {0}", anyAction.Method.ReturnType);
}
Because the signature isn't type specific, you have to pass the specific delegates this time (Why? See this answer):
AcceptAnyDelegate(action1);
AcceptAnyDelegate(action2);
And the output would be:
The function returns a Void
The function returns a Boolean
Edit
After rereading your comments, I believe the confusion here is due to a misunderstanding of method groups and delegates.
When you write something like this:
Foo(Bar);
...it appears you believe you are passing to Foo a direct reference to the Bar method. That is not correct. What you are doing is specifying a method group, which the compiler can then use to infer the type of delegate to pass. If Bar is a method with no inputs or outputs, the above code is exactly the same as
Foo(new Action( Bar ));
...only the creation of the delegate is hidden from you by the compiler.
All delegates are specifically typed with respect to their parameters and return type. The Delegate base type is abstract and cannot exist in concrete form. So there is no such thing as passing a type-agnostic function reference-- it doesn't exist in c#.
If you really really want to pass something that is type-agnostic, you can ask the caller to pass a lambda expression:
Foo( () => SomeFunction1() );
You could then parse the expression to figure out the method's inputs and outputs:
void Foo(Expression<Action> anyAction)
{
var mce = anyAction.Body as MethodCallExpression;
var method = mce.Method;
Console.WriteLine("The method has a return type of {0}", method.ReturnType.Name);
}
Then to invoke the expression you would use:
var compiled = anyAction.Compile();
compiled();
That is the closest you're going to get.
There's two different types here:
Action for no return type
and
Func for a return type
Can you make two different signatures for these two different argument types?
This will do the trick
public static void TakeInAFunc<T>(T aFuncOrAction)
{
if (typeof(T) == typeof(Func<>))
{
// some value returned.
}
else if (typeof(T) == typeof(Action<>))
{
// it returns void.
}
}
How does Select(int.Parse) work in such Linq expression?
"1,2,3,4,5".Split(',').Select(int.Parse).ToList(); //ok
"1,2,3,4,5".Split(',').Select(x => int.Parse(x)).ToList(); //ok
Why example with Console.Writeline returns compilation error?
"1,2,3,4,5".Split(',').Select(Console.WriteLine).ToList(); //error
"1,2,3,4,5".Split(',').Select(x => Console.WriteLine(x)).ToList(); //ok
When it is allowed to omit lambda like (x => ....(x))
Console.WriteLine as well as int.Parse are so-called method groups. Groups of methods. Because of the various overloads of those methods. It can be exactly one method, or multiple methods.
A method group can be converted to a delegate if the compiler can infer which method of the group is meant. For example the method group int.Parse can be a delegate to int.Parse(string) if a Func<string, int>is expected.
This works in your first example. Select expects a Func<T, T2> and your T is already set to be of type string. However, it does not work with your second example. Because while Console.WriteLine is a method group, not a single method in this group corresponds to the required Func<T, T2> because the return type of all of the methods in the group is void.
The signature of Select looks somewhat like this:
public static IEnumerable<TResult> Select<TSource, TResult>(
this IEnumerable<TSource> source,
Func<TSource, TResult> selector);
So for the selector a method (or lambda) with the signature
TResult Method(string s);
is expected. Console.WriteLine() is of return type void which is not a valid type for TResult. So in fact both lines:
"1,2,3,4,5".Split(',').Select(Console.WriteLine).ToList();
"1,2,3,4,5".Split(',').Select(x => Console.WriteLine(x)).ToList();
don't compile. Are you sure you really compiled that second line? My compiler raises error CS0411 for both lines.
Select is a projections statement, it transforms your object into a new object that you specify inside the Select.You need to loop and execute the WriteLine:
"1,2,3,4,5".Split(',').ToList().ForEach(x=> { Console.WriteLine(x); });
Select expects a parameter Func<char, T>, Console.WriteLine doesn't match that.
Almost all LINQ extensions accept a function that returns a value. Console.WriteLine does not return anything, so it can't be used as parameter.
"12345".Select(x => { Console.WriteLine(x); return x; }).ToList(); // this will work
"12345".Select(int.TryParse).ToList(); // this will NOT work because TryParse needs more than one parameter
"12345".ToList().ForEach(Console.WriteLine); // this will work because .ForEach accepts a method that does not return anything (void)
"12345".ToList().ForEach(int.Parse); // this will NOT work
It's allowed when the method signature is the same as LinQ expects.
In your first case, the Select's expected signature a method with one string parameter and return value of int (or simply Func<string, int>) and int.Parse method has the same signature, that's why it's working;
while in the second case, the Console.WriteLine's signature is a method with one string parameter and no return value (or return value of special type void) (or simply Action<string>), and hence signature that Select expects and signature that Console.WriteLine has do not match.
Say I have a method that calls another method that accepts a string and returns a string, over and over until a condition is met:
public string RetryUntil(
Func<string, string> method,
string input,
Func<string, bool> condition,
TimeSpan timeSpan)
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
string response = string.Empty;
bool conditionResult = false;
while (stopwatch.Elapsed < timeSpan && conditionResult != true)
{
result = method(input);
conditionResult = condition(result);
Thread.Sleep(TimeSpan.FromSeconds(0.5));
}
return response;
}
It really feels like I should be able to specify the 'method' and 'input' parameters as one parameter. So, I want to refactor it so I am able to call it like this, for example:
RetryUntil(
ConvertString("hello World"),
(str) => { return str == "whatever"; },
TimeSpan.FromSeconds(10));
But obviously, this would pass the result of calling the ConvertString method, (rather than just a delegate to that method) into the Retry method. Is there a way to pass both delegates and specific parameters for those delegates as one? Am I thinking about the entire problem backwards? It just feels a bit inelegant the way I'm doing it now.
What you're looking for is often called "currying" and is not directly supported in C#, or at least not as well as it is in F#. This is a feature where you can specify some arguments of a function, and get a delegate which takes the remaining arguments (if any) and returns the appropriate value.
The easiest way to reference this is like so:
public string RetryUntil(
Func<string> method,
Func<string, bool> condition,
TimeSpan timeSpan)
And then call via
RetryUntil(
() => ConvertString("Hello World!"),
// ...
the => creates a lambda, which will return the result of the given function. Since you're now declaring a method call, you can pass in whatever parameters you wish, or make the lambda itself take some parameters, thus currying arguments.
I have a generic function CallLater that should accept an arbitrary other function and possibly call it later with some parameters. All kind of functions should be supported - static, instance, private, public. Parameters are analyzed and constructed dynamically in CallLater with the help of reflection. However, some of them may need to be bound to fixed values before passing the function to the CallLater.
For example:
void CallLater(Delegate d) {
// Expects a function that returns string and has one argument of arbitrary type.
if (d.Method.GetParameters().Length == 1 &&
d.Method.ReturnType == typeof(string)) {
object param1 = Activator.CreateInstance(d.Method.GetParameters()[0].ParameterType);
Console.WriteLine((string)d.DynamicInvoke(param1));
}
}
// Has one extra float parameter.
string MyFunc(int a, float b) { ... }
My idea was to do something like that:
float pi = 3.14f;
CallLater(delegate(int a) { return MyFunc(a, pi); });
But this doesn't work as compiler complains:
Error CS1660: Cannot convert `anonymous method' to non-delegate type `System.Delegate' (CS1660) (test-delegate)
What is the correct approach to achieve my goal?
P.S. Please do not offer the solution to declare a fixed delegate type as CallLater is way more complex and may support variable number of arguments too.
P.P.S. It might be that my solution is Func, but I wasn't able to use it on Mono so far.
You can always redeclare Func yourself:
public delegate TReturn FFunc<TArg,TReturn>(TArg arg);
Which you can use thusly:
float pi = 3.14f;
CallLater((FFunc<int,string>)(delegate(int a) { return MyFunc(a, pi); }));
I'd suggest using anonymous functions in which you call the method you want to execute. These are executed later when the anonymous method is executed.
private static void ExecuteBoolResult(Func<bool> method)
{
bool result = method();
if (!result)
{
throw new InvalidOperationException("method did not return true");
}
}
CheckBoolResult(() => AnotherFunction("with ", 3, " parameters"));
CheckBoolResult(() => AnotherFunction(2, "parameters"));
I need explanations.. why the following code give an: Parameter count mismatch ?
C# Code:
//...
public delegate int FindInRichTextBoxMethod(RichTextBox rtx, string target, int index);
public int FindInRichTextBox(RichTextBox rtx, string target, int index)
{
return rtx.Find(target, index, RichTextBoxFinds.None);
}
// ...
int start;
string tempState = "foo";
if (lista.InvokeRequired) {
object find = Invoke((FindInRichTextBoxMethod)delegate
{
return FindInRichTextBox(list, tempState, len);
});
start = (int)find;
} else {
start = FindInRichTextBox(list, tempState, len);
}
Thanks in advance.
The arguments to Invoke() include a delegate, and the arguments passed to that delegate. You're attempting to pass a FindInRichTextBoxMethod delegate, but that delegate type takes three arguments. You need to:
construct a delegate with your FindInRichTextBox method, and then
pass in the parameters to that delegate.
Something like this:
var finder = new FindInRichTextBoxMethod(FindInRichTextBox);
object find = Invoke(finder, new object[] { list, tempState, len });
Another route is to pass in a closure, sort of like you're attempting in your sample. In your case the error is due to the cast to a FindInRichTextBoxMethod, so the Invoke is expecting arguments. Instead, you could ignore the cast and pass in an anonymous delegate like this:
var find = Invoke(delegate { return FindInRichTextBox(list, tempState, len); });
This won't work, though, because the compiler can't determine exactly what you want to do with that anonymous delegate. Similarly, a lambda can't be automatically converted either:
var find = Invoke(() => FindInRichTextBox(list, tempState, len));
To see why and how to fix the problem, read Why must a lambda expression be cast when supplied as a plain Delegate parameter.
Are you getting this in the Invoke call? I usually pass Invoke a delegate and then an object array containing the variables you want to pass.