Конвертировать Func <T, String> в Func <T, bool> - PullRequest
13 голосов
/ 21 августа 2011

Я думаю, что мой ум взрывается, пытаясь понять Funcs ... Если это не имеет смысла, прошу прощения, сейчас это имеет смысл для меня, но это был уже долгий день ...

1) Предполагается, что вы получили функцию, которая принимает T и выводит строку:

 Func<T, string> 

Можете ли вы преобразовать это в функцию, которая принимает T и возвращает логическое значение на основе некоторой логики (в этом случае, если возвращаемая строка пуста (String.IsNullOrWhiteSpace)?

 Func<T, bool> 

2) Можете ли вы сделать то же самое, если вам дали

Expression<Func<T, string>>

и нужно преобразовать его в

Func<T, bool>

, который возвращает истину / ложь в зависимости от того, является ли возвращенная строка пустой (String.IsNullOrWhiteSpace)?

Спасибо

Ответы [ 4 ]

11 голосов
/ 21 августа 2011

для первой части вы можете даже сделать некоторую функцию «более высокого» порядка:



Func<A,C&gt MapFun<A,B,C&gt(Func<A,B&gt input, Func<B,C&gt transf)
{
   return a => transf(input(a));
}

использовать с



Func <T,string> test = ...
var result = MapFun(test, String.IsNullOrWhiteSpace);

(надеюсь, здесь работает вывод типа C #)

Если вы определите это как расширение в Func, это станет еще проще:


public static class FuncExtension
{
    public static Func<A,C> ComposeWith<A,B,C&gt(this Func<A,B> input, Func<B,C> f)
    {
         return a => f(input(a));
    }
}

вот очень простой тест:


Func<int, string&gt test = i =&gt i.ToString();
var result = test.ComposeWith(string.IsNullOrEmpty);

Для второго: я думаю, что вы можете скомпилировать выражение в «настоящий» Func и затем использовать приведенный выше код. см. Документы MSDN по Expression.Compile

PS: переименована функция, чтобы лучше соответствовать ее назначению (состав функции)

3 голосов
/ 21 августа 2011

Не могли бы вы определить его как отдельный делегат:

Func<T, string> func1 = t => t.ToString();
Func<T, bool> func2 = t => string.IsNullOrEmpty(func1(t));
2 голосов
/ 21 августа 2011

К 1: Да (Вы также можете параметризовать bool и string):

Func<T, bool> Compose<T>(Func<T, string> source, Func<string, bool>map)
{
    return x => map(source(x));
}

To 2: Да, но сначала нужно скомпилировать выражение:

Func<T, bool> Compose<T>(Expression<Func<T, string>> source, Func<string, bool> map)
{
    return x => compose(source.Compile(), map)
}

.Compile скомпилирует выражение в динамический метод CLR, который вы можете вызвать с возвращенным делегатом.

Вы можете использовать этот код так:

Func<int, string> ts = i => i.ToString();
var result = Compose(ts, string.IsNullOrEmpty);

Кстати, в этом случае вы действительно должны написать функцию более высокого порядка. То, что вы делаете здесь (алгебраически) - это сочинение моноидов. Помните функция композиции ? f . g := f(g(x)) это то, что вы делаете здесь.

Думайте об источнике как g:A->B и отображайте как f:B->C (где A, B и C - наборы), поэтому результат f . g равен h:A->C. Кстати, оператор . часто встроен в функциональные языки программирования, такие как Haskell, и выполняет те же функции, что и ваша функция compose (но с более чистым синтаксисом).

2 голосов
/ 21 августа 2011

Для первой части этот метод известен как композиция функций, т.е. вы создаете 2 функции для создания новой функции. В вашем случае у вас есть функция Func<T,String> и другая функция (например, строка пустая или пустая), которая имеет тип Func<string,bool>, используя композицию функций, вы можете объединить эти две функции, чтобы создать новую функцию типа Func<T,Bool>

Большинство функциональных языков программирования имеют такой набор функций, уже определенный в их стандартной библиотеке или в самом языке. Но не сложно создать его для вашего языка, если язык поддерживает функции в качестве значений первого класса.

В C # вы можете использовать следующую функцию, которая позволит вам составлять функции:

public static Func<X,Z> Compose<X,Y,Z>(Func<X,Y> a, Func<Y,Z> b)
{
    return (v) => b(a(v));
}
...