How do I describe an Action<T> delegate that returns a value (non-void)? - c#

The Action<T> delegate return void. Is there any other built-in delegate which returns non void value?

Yes. Func<> returns the type specified as the final generic type parameter, such that Func<int> returns an int and Func<int, string> accepts an integer and returns a string. Examples:
Func<int> getOne = () => 1;
Func<int, string> convertIntToString = i => i.ToString();
Action<string> printToScreen = s => Console.WriteLine(s);
// use them
printToScreen(convertIntToString(getOne()));

Sure, the Func Delegates return T.
Func<TResult> is "TResult method()"
Func<TInput, TResult> is "TResult method(TInput param)"
All the way down to
Func<T1, T2, T3, T4, TResult>
http://msdn.microsoft.com/en-us/library/bb534960.aspx
http://msdn.microsoft.com/en-us/library/bb534303.aspx
Also, for the sake of completeness, there is Predicate which returns bool.
Predicate<T> is "bool method(T param)"
http://msdn.microsoft.com/en-us/library/bfcke1bz.aspx

Related

Generic method with Func parameter, Func contravariance doesn't seem to work

.NET's Func<T1, T2, TResult> is written so that T1 and T2 are contravariant and TResult is covariant.
This means that:
Func<object, object, bool> objectEquals = object.Equals;
Func<MyObject, MyObject, bool> myObjectEquals = objectEquals;
is a valid assignment.
Now, I have a class with methods along these lines:
public void DoSomething<T>(T value)
{
DoSomethingCore(T, Object.Equals);
}
protected abstract void DoSomethingCore<T>(T value, Func<T, T, bool> equals);
The code would not compile, with the following error:
CS0123 No overload for 'object.Equals(object, object)' matches delegate 'Func<T, T, bool>'
Why does contravariance not seem to work in this case?
Contravariance, and variance in general, don't work with value types.
Hence, you must constrain the DoSomething method to only work with reference types if you want to use Object.Equals as the function for Func<T, T, bool>.
In other words, add where T : class in the method signature:
public void DoSomething<T>(T value) where T : class
{
DoSomethingCore(T, Object.Equals);
}

Convert Func<object, Task> to Func<T, Task> at runtime

I have a Func<object, Task>. I am trying to pass it as an argument into a function that takes Func<T, Task>. I am using reflection to create a MethodInfo for the function, and the T being filled in is not known until runtime.
How can I do this with reflection?
You don't need to do anything special.
Func<in T, out TResult> is contravariant on T - its input parameter, and every type inherits from object, which means you can just cast Func<object, Task> to Func<T, Task> for any reference type T - pass it as-is and it will just work.
Example
Now, this won't work for value types, since those require unboxing beforehand.
So if your T is a value type, you'll have to wrap it in another delegate which will perform a cast.
One simple way would be to define a wrapper method:
private static Func<T, TResult> CastFunc<T, TResult>(Func<object, TResult> fn)
=> param => fn(param);
Then create a delegate through reflection:
var result = (Func<int, Task>)typeof(WrapperClass)
.GetMethod(nameof(CastFunc), BindingFlags.NonPublic | BindingFlags.Static)
.MakeGenericMethod(typeof(int), typeof(Task)).Invoke(null, new object[] { fn });
I'd go for reflection using MakeGenericMethod
Here's a quick example:
public class Example
{
public void Start()
{
Func<object, Task> func = o => null;
object objFunc = func; // got it from a generic place as an object or something
Type type = objFunc.GetType().GetGenericArguments()[0]; // get T in runtime
var method = typeof(Example).GetMethod("DoSomething", BindingFlags.Public | BindingFlags.Instance).MakeGenericMethod(type);
var result = method.Invoke(this, new object[1] { func });
}
public int DoSomething<T>(Func<T, Task> input)
{
return 1;
}
}

how to implement Action<..> as Func<...>

I'd like to implement Action as func and get the error : could not use void in this context.
Please advise
Action<string> someFunc_1 = Console.WriteLine;
someFunc_1("Test");
Func<string, void> someFunc_2 = Console.WriteLine;
Action<T1, T2, ...> is done to replace Func<T1, T2, ..., void>.
You can't use void in a generic. It's not a type in C#.
Then in your case, use Action<string> instead of Func<string, void>.
Func<string, bool> someFunc_2 = s =>
{
Console.WriteLine(s);
return true;
};

Can a lambda expression be declared and invoked at the same time in C#?

In VB.NET, a lambda expression can be declared and invoked on the same line:
'Output 3
Console.WriteLine((Function(num As Integer) num + 1)(2))
Is this possible in C#?
You have to tell the compiler a specific delegate type. For example, you could cast the lambda expression:
Console.WriteLine(((Func<int, int>)(x => x + 1))(2));
EDIT: Or yes, you can use a delegate creation expression as per Servy's answer:
Console.WriteLine(new Func<int, int>(i => i + 1)(2));
Note that this isn't really a normal constructor call - it's special syntax for delegate creation which looks like a regular constructor call. Still clever though :)
You can make it slightly cleaner with a helper class:
public static class Functions
{
public static Func<T> Of<T>(Func<T> input)
{
return input;
}
public static Func<T1, TResult> Of<T1, TResult>
(Func<T1, TResult> input)
{
return input;
}
public static Func<T1, T2, TResult> Of<T1, T2, TResult>
(Func<T1, T2, TResult> input)
{
return input;
}
}
... then:
Console.WriteLine(Functions.Of<int, int>(x => x + 1)(2));
Or:
Console.WriteLine(Functions.Of((int x) => x + 1)(2));
Console.WriteLine(new Func<int, int>(i => i + 1)(2));
Uses a few less parentheses to use the Func's constructor than a cast.
Yes, though it's messy:
Console.WriteLine(((Func<int, int>) (num => num + 1))(2));
Kind or, you would have to use the Func object :
var square = new Func<double, double>(d => d*d)(2);
Console.WriteLine(square);

Func<T> with out parameter

Can I pass a method with an out parameter as a Func?
public IList<Foo> FindForBar(string bar, out int count) { }
// somewhere else
public IList<T> Find(Func<string, int, List<T>> listFunction) { }
Func needs a type so out won't compile there, and calling listFunction requires an int and won't allow an out in.
Is there a way to do this?
ref and out are not part of the type parameter definition so you can't use the built-in Func delegate to pass ref and out arguments. Of course, you can declare your own delegate if you want:
delegate V MyDelegate<T,U,V>(T input, out U output);
Why not create a class to encapsulate the results?
public class Result
{
public IList<Foo> List { get; set; }
public Int32 Count { get; set; }
}
The Func family of delegates (or Action for that matter) are nothing but simple delegate types declared like
//.NET 4 and above
public delegate TResult Func<out TResult>()
public delegate TResult Func<in T, out TResult>(T obj)
//.NET 3.5
public delegate TResult Func<T1, T2, TResult>(T1 obj1, T2 obj2)
public delegate TResult Func<T1, T2, T3, TResult>(T1 obj1, T2 obj2, T3 obj3)
etc. Delegates as such can have out/ref parameters, so in your case its only a matter of custom implementation by yourself as other answers have pointed out. As to why Microsoft did not pack this by default, think of the sheer number of combinations it would require.
delegate TResult Func<T1, T2, TResult>(T1 obj1, T2 obj2)
delegate TResult Func<T1, T2, TResult>(out T1 obj1, T2 obj2)
delegate TResult Func<T1, T2, TResult>(T1 obj1, out T2 obj2)
delegate TResult Func<T1, T2, TResult>(out T1 obj1, out T2 obj2)
for just two parameters. We have not even touched ref. It would actually be cumbersome and confusing for developers.
You could wrap it in a lambda/delegate/function/method that exposed the right interface and called FindForBar, but I suspect that FindForBar has count as an out parameter as a reason, so you'd need to be sure throwing that information away was ok/safe/desirable/had the right results (you'd need to be sure of this even if you could just directly pass in FindForBar).

Categories