Func <T> sin parámetro


167

¿Puedo pasar un método con un parámetro de salida como Func?

public IList<Foo> FindForBar(string bar, out int count) { }

// somewhere else
public IList<T> Find(Func<string, int, List<T>> listFunction) { }

Func necesita un tipo para que out no se compile allí, y llamar a listFunction requiere un int y no permitirá una entrada.

¿Hay alguna forma de hacer esto?

Respuestas:


228

refy outno forman parte de la definición de parámetro de tipo, por lo que no puede usar el Funcdelegado incorporado para pasar refy outargumentos. Por supuesto, puede declarar su propio delegado si desea:

delegate V MyDelegate<T,U,V>(T input, out U output);

77
En C # 4 (2010) y posteriores (no se publicó cuando escribió su respuesta) es posible marcar Tcomo contravariante y Vcomo covariante. Sin embargo, dado que un parámetro ( output) de tipo Use pasa por referencia , Uno se puede marcar como co o contravariante y debe permanecer "invariante". Así que considere public delegate V MyDelegate<in T, U, out V>(T input, out U output);si usa C # 4 o posterior.
Jeppe Stig Nielsen


24

¿Por qué no crear una clase para encapsular los resultados?

public class Result
{
     public IList<Foo> List { get; set; }
     public Int32 Count { get; set; }
}

13

La Funcfamilia de delegados (o Actionpara el caso) no son más que simples tipos de delegados declarados como

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

Los delegados como tales pueden tener parámetros out / ref, por lo que en su caso es solo una cuestión de implementación personalizada por usted mismo, como lo han señalado otras respuestas. En cuanto a por qué Microsoft no empacó esto por defecto, piense en la gran cantidad de combinaciones que requeriría.

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)

por solo dos parámetros. Ni siquiera nos hemos tocado ref. En realidad, sería engorroso y confuso para los desarrolladores.


2
Tenga en cuenta que la sobrecarga de la función C # no puede distinguir entre delegate TResult Func<T1, T2, TResult>(T1 obj, T2 obj)y delegate TResult Func<T1, T2, TResult>(out T1 obj, T2 obj). Por lo tanto, además del número de símbolo de sobrecargas, hay otra razón por la cual Microsoft no pudo agregar estas sobrecargas Func.
Kasper van den Berg

¿Alguien puede referirme a un artículo de MSDN sobre los delegados anteriores?
Su Llewellyn

@SuLlewellyn No pude encontrar el artículo original de msdn, pero puedes probar: docs.microsoft.com/en-us/dotnet/api/… , docs.microsoft.com/en-us/dotnet/api/…
nawfal

0

Podría envolverlo en un método lambda / delegado / función / que expuso la interfaz correcta y llamó a FindForBar, pero sospecho que FindForBar cuenta como un parámetro de salida como una razón, por lo que debe asegurarse de tirar esa información ok / seguro / deseable / tuvo los resultados correctos (tendría que estar seguro de esto incluso si pudiera pasar directamente en FindForBar).

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.