2009-08-15 20 views
134

¿Puedo pasar un método con un parámetro out como Func?Func <T> sin el parámetro

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 tan fuera no se compilará allí, y listFunction llamando requiere un int y no permitirá una salida en.

¿Hay una manera de hacer esto?

Respuesta

192

ref y out no son parte de la definición del parámetro de tipo por lo que no puede utilizar el incorporado en Func delegado para pasar ref y out argumentos. Por supuesto, puede declarar su propio delegado si quieres:

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

En caso de que alguien más esté confundido como yo, no * tiene * que llamar a su delegado "Func" como los integrados ... – Dunc

+0

@Dunc - Solucionado. Hubiera estado realmente confundido si no fuera por tu comentario. –

+5

En C# 4 (2010) y posterior (no se publicó cuando escribió su respuesta) es posible marcar 'T' como contravariante, y' V' como covariante. Sin embargo, dado que un parámetro ('output') de tipo' U' se pasa *** por la referencia ***, 'U' no se puede marcar co o contravariante y debe permanecer como" invariante ". Por lo tanto, considere 'delegado público V MyDelegate (T input, out U output);' si usa C# 4 o posterior. –

19

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

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

Se podría envolverlo en un/función/método lambda/delegado que expone la interfaz correcta y FindForBar llamada, pero sospecho que ha FindForBar contar como un parámetro de salida como una razón, por lo que había necesidad de asegúrese de arrojar esa información de forma correcta/segura/deseable/tuvo los resultados correctos (deberá estar seguro de esto incluso si pudiera pasar directamente FindForBar).

9

El Func familia de los delegados (o Action para el caso) no son más que simples tipos de delegado 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) 

etc. Delegados como tal, puede tener parámetros out/ref, por lo que en su caso solo es una cuestión de implementación personalizada, como lo han señalado otras respuestas. En cuanto a por qué Microsoft no empaquetó 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 hemos tocado ref. En realidad, sería engorroso y confuso para los desarrolladores.

+1

Tenga en cuenta que la función de sobrecarga de C# no puede distinguir entre 'delegar TResult Func (T1 obj, T2 obj) 'y' delegar TResult Func (out T1 obj, T2 obj) '. Entonces, además del número de sobrecargas del nombre del símbolo, hay otra razón por la cual Microsoft no pudo agregar estas sobrecargas de 'Func'. –

Cuestiones relacionadas