2009-08-15 2 views
134

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

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

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

Func нужен тип так из не скомпилируется там, и вызов listFunction требует Int и не позволит амбулаторному в.

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

ответ

192

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

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

В случае, если кто-то смущен, как и я, вы не имеете *, чтобы называть своего делегата «Func», как встроенные ... – Dunc

+0

@ Dunc - Исправлено. Я бы смутился, если бы не ваш комментарий. –

+5

В C# 4 (2010) и позже (не был выпущен, когда вы написали свой ответ), можно пометить 'T' как контравариантную, а' V' - ковариантной. Однако, поскольку параметр ('output') типа' U' передается *** по ссылке ***, 'U' не может быть отмечен ко- или контравариантным и должен оставаться« инвариантным ». Поэтому рассмотрим 'public delegate V MyDelegate (вход T, выход U);' если вы используете C# 4 или новее. –

19

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

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

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

9

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. Это на самом деле было бы громоздким и запутанным для разработчиков.

+1

Обратите внимание, что перегрузка функции C# не может различать «делегировать TResult Func (T1 obj, T2 obj)» и «делегировать TResult Func (out T1 obj, T2 obj)». Таким образом, кроме того, количество имен символов перегрузки является другой причиной того, почему Microsoft не может добавить эти перегрузки 'Func'. –

Смежные вопросы