Func <T> sem parâmetro

167

Posso passar um método com um parâmetro out como um Func?

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

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

O Func precisa de um tipo para que a saída não seja compilada lá, e chamar listFunction requer um int e não permitirá a entrada.

Existe uma maneira de fazer isso?

azul
fonte

Respostas:

228

refe outnão fazem parte da definição de parâmetro type, portanto você não pode usar o Funcdelegado interno para passar refe outargumentos. Obviamente, você pode declarar seu próprio delegado se desejar:

delegate V MyDelegate<T,U,V>(T input, out U output);
Mehrdad Afshari
fonte
7
No C # 4 (2010) e posterior (não foi lançado quando você escreveu sua resposta), é possível marcar Tcomo contravariante e Vcovariante. No entanto, como um parâmetro ( output) do tipo Ué passado por referência , Unão pode ser marcado como co- ou contravariante e deve permanecer "invariante". Portanto, considere public delegate V MyDelegate<in T, U, out V>(T input, out U output);se você usa C # 4 ou posterior.
Jeppe Stig Nielsen
24

Por que não criar uma classe para encapsular os resultados?

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

A Funcfamília de delegados (ou, Actionnesse caso) não passa de 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)

etc. Os delegados, como tais, podem ter parâmetros out / ref, portanto, no seu caso, é apenas uma questão de implementação personalizada por você, como outras respostas indicaram. Por que a Microsoft não empacotou isso por padrão, pense no grande número de combinações necessárias.

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 apenas dois parâmetros. Nós nem nos tocamos ref. Seria realmente complicado e confuso para os desenvolvedores.

nawfal
fonte
2
Observe que a sobrecarga da função C # não pode distinguir entre delegate TResult Func<T1, T2, TResult>(T1 obj, T2 obj)e delegate TResult Func<T1, T2, TResult>(out T1 obj, T2 obj). Portanto, além do número de sobrecargas, o nome do símbolo é outro motivo pelo qual a Microsoft não pôde adicionar essas sobrecargas Func.
Kasper van den Berg
Alguém pode me indicar um artigo do MSDN sobre os delegados acima?
Su Llewellyn
@SuLlewellyn Não consegui encontrar o artigo original do msdn, mas você pode tentar: docs.microsoft.com/en-us/dotnet/api/… , docs.microsoft.com/en-us/dotnet/api/…
nawfal
0

Você poderia envolvê-lo em um lambda / delegate / function / method que expôs a interface correta e chamou FindForBar, mas eu suspeito que o FindForBar tenha contagem como parâmetro out como motivo, portanto, você deve ter certeza de que essas informações foram descartadas. ok / safe / desejável / teve os resultados corretos (você precisaria ter certeza disso, mesmo que pudesse passar diretamente diretamente para FindForBar).

Logan Capaldo
fonte