Func<T> with out parameter
Asked Answered
D

4

207

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?

Dissimilate answered 15/8, 2009 at 23:45 Comment(0)
C
262

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);
Cryptonym answered 15/8, 2009 at 23:54 Comment(2)
In C# 4 (2010) and later (was not released when you wrote your answer) it is possible to mark T as contravariant, and V as covariant. However, since a parameter (output) of type U is passed by reference, U cannot be marked co- or contravariant and must remain "invariant". So consider public delegate V MyDelegate<in T, U, out V>(T input, out U output); if you use C# 4 or later.Turnout
See this example for using ref parameter with in and out parameters.Hoe
L
28

Why not create a class to encapsulate the results?

public class Result
{
     public IList<Foo> List { get; set; }
     public Int32 Count { get; set; }
}
Ledford answered 15/8, 2009 at 23:51 Comment(1)
Because newing-up a class object for every result will incur the GC tax, which is significant for high-frequency operations (so consider using ValueTuple instead).Dagmardagna
A
18

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.

Anabel answered 13/12, 2013 at 6:26 Comment(3)
Note that C# function overloading cannot distinguish between delegate TResult Func<T1, T2, TResult>(T1 obj, T2 obj) and delegate TResult Func<T1, T2, TResult>(out T1 obj, T2 obj). So besides the number of overloads symbol name are an other reason for why Microsoft could not add these overloads of Func.Pussy
Can someone refer me to an MSDN article on the delegates above?Minoan
@SuLlewellyn I couldnt find the original msdn article, but you could try: learn.microsoft.com/en-us/dotnet/api/…, learn.microsoft.com/en-us/dotnet/api/…Anabel
S
0

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

Spiritless answered 15/8, 2009 at 23:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.