Func <T> sans paramètre out

167

Puis-je passer une méthode avec un paramètre out comme Func?

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

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

Func a besoin d'un type pour que out n'y soit pas compilé, et l'appel de listFunction nécessite un int et n'autorisera pas un out in.

Y a-t-il un moyen de faire cela?

blu
la source

Réponses:

228

refet outne font pas partie de la définition du paramètre de type de sorte que vous ne pouvez pas utiliser le intégré Funcdélégué pour passer refet outarguments. Bien sûr, vous pouvez déclarer votre propre délégué si vous le souhaitez:

delegate V MyDelegate<T,U,V>(T input, out U output);
Mehrdad Afshari
la source
7
Dans C # 4 (2010) et versions ultérieures (n'a pas été publié lorsque vous avez écrit votre réponse), il est possible de marquer Tcomme contravariant et Vcomme covariant. Cependant, comme un paramètre ( output) de type Uest passé par référence , Uil ne peut pas être marqué co- ou contravariant et doit rester "invariant". Considérez donc public delegate V MyDelegate<in T, U, out V>(T input, out U output);si vous utilisez C # 4 ou une version ultérieure.
Jeppe Stig Nielsen
24

Pourquoi ne pas créer une classe pour encapsuler les résultats?

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

La Funcfamille de délégués (ou Actiond'ailleurs) n'est rien d'autre que de simples types de délégués déclarés comme

//.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. Les délégués en tant que tels peuvent avoir des paramètres out / ref, donc dans votre cas ce n'est qu'une question d'implémentation personnalisée par vous-même comme d'autres réponses l'ont souligné. Quant à savoir pourquoi Microsoft n'a pas emballé cela par défaut, pensez au nombre de combinaisons qu'il faudrait.

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)

pour seulement deux paramètres. Nous n'avons même pas touché ref. Ce serait en fait encombrant et déroutant pour les développeurs.

nawfal
la source
2
Notez que la surcharge de la fonction C # ne peut pas faire la distinction entre delegate TResult Func<T1, T2, TResult>(T1 obj, T2 obj)et delegate TResult Func<T1, T2, TResult>(out T1 obj, T2 obj). Donc, outre le nombre de surcharges, le nom du symbole est une autre raison pour laquelle Microsoft n'a pas pu ajouter ces surcharges de Func.
Kasper van den Berg
Quelqu'un peut-il me référer à un article MSDN sur les délégués ci-dessus?
Su Llewellyn
@SuLlewellyn Je n'ai pas pu trouver l'article msdn d'origine, mais vous pouvez essayer: docs.microsoft.com/en-us/dotnet/api/… , docs.microsoft.com/en-us/dotnet/api/…
nawfal
0

Vous pouvez l'envelopper dans un lambda / délégué / fonction / méthode qui a exposé la bonne interface et appelé FindForBar, mais je soupçonne que FindForBar a compté comme un paramètre out comme raison, vous devez donc être sûr de jeter ces informations ok / sûr / souhaitable / a eu les bons résultats (vous devez être sûr de cela même si vous pouvez simplement passer directement dans FindForBar).

Logan Capaldo
la source