Func <T> без параметра

167

Могу ли я передать метод с параметром out как Func?

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

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

Для Func нужен тип, поэтому out не будет компилироваться, а для вызова listFunction требуется int и не будет разрешен вход.

Есть ли способ сделать это?

голуб
источник

Ответы:

228

refи outне являются частью определения параметра типа, поэтому вы не можете использовать встроенный Funcделегат для передачи refи outаргументов. Конечно, вы можете объявить свой собственный делегат, если хотите:

delegate V MyDelegate<T,U,V>(T input, out U output);
Мехрдад Афшари
источник
7
В C # 4 (2010) и позже (не был выпущен, когда вы написали свой ответ) его можно пометить Tкак контравариантный и Vковариантный. Однако, поскольку параметр ( output) типа Uпередается по ссылке , он Uне может быть помечен как со-или контравариантный и должен оставаться «инвариантным». Так что подумайте, используете public delegate V MyDelegate<in T, U, out V>(T input, out U output);ли вы C # 4 или новее.
Джеппе Стиг Нильсен
24

Почему бы не создать класс для инкапсуляции результатов?

public class Result
{
     public IList<Foo> List { get; set; }
     public Int32 Count { get; set; }
}
ChaosPandion
источник
13

FuncСемья делегатов (или Actionв этом отношении) не что иное , как простые типы делегатов , объявленные как

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

и т. д. Делегаты как таковые могут иметь параметры out / ref, поэтому в вашем случае это только вопрос индивидуальной реализации, как указали другие ответы. Что касается того, почему Microsoft не упаковала это по умолчанию, подумайте о том, какое количество комбинаций ей потребуется.

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)

только для двух параметров. Мы даже не трогали ref. Это на самом деле было бы громоздким и запутанным для разработчиков.

Навфал
источник
2
Обратите внимание, что перегрузка функции C # не может различить delegate TResult Func<T1, T2, TResult>(T1 obj, T2 obj)и delegate TResult Func<T1, T2, TResult>(out T1 obj, T2 obj). Таким образом, помимо количества перегрузок имя символа является еще одной причиной, по которой Microsoft не может добавить эти перегрузки Func.
Каспер ван ден Берг
Может кто-нибудь отослать меня к статье MSDN о делегатах выше?
Су Ллевеллин
@SuLlewellyn Я не смог найти оригинальную статью msdn , но вы можете попробовать: docs.microsoft.com/en-us/dotnet/api/… , docs.microsoft.com/en-us/dotnet/api/…
nawfal
0

Вы могли бы обернуть его в лямбда / делегат / функцию / метод, который выставил правильный интерфейс и вызвал FindForBar, но я подозреваю, что FindForBar имеет значение в качестве параметра out в качестве причины, поэтому вам нужно быть уверенным, что выбрасывание этой информации было ОК / безопасно / желательно / дали правильные результаты (вам нужно быть уверенным в этом, даже если вы могли бы просто напрямую перейти в FindForBar).

Логан Капальдо
источник