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; }
}

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.