2011-08-21 4 views
13

Je pense que mon esprit explose en essayant de comprendre Funcs ... Si cela n'a aucun sens, je m'excuse, en ce moment, il me semble logique, mais il a déjà été une longue journée ....Convert Func

1) en supposant que vous donne une func qui prend en T et génère une chaîne:

Func<T, string> 

Pouvez-vous transformer cela en une func qui prennent en T et retourne un bool basé sur une certaine logique (en ce cas si la chaîne renvoyée est vide (String.IsNullOrWhiteSpace)?

Func<T, bool> 

2) Pouvez-vous faire la même chose si vous êtes donné un

Expression<Func<T, string>> 

et la nécessité de le convertir en un

Func<T, bool> 

qui retourne vrai/faux sur la base si la chaîne retournée est vide (String.IsNullOrWhiteSpace)?

Merci

Répondre

11

pour la première partie, vous pouvez même faire quelques "plus" fonction -order:



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

utilisation avec



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

(j'espère que l'inférence de type C# type travaille ici)

Si vous définissez cela comme l'extension sur Func il devient encore plus facile:


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

ici est un test très simple:


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

Pour le second: je pense que vous pouvez compiler l'expression dans un "vrai" Func et ensuite utiliser le code ci-dessus. see MSDN Docs on Expression.Compile

PS: renommé la fonction pour mieux correspondre à son intention (sa composition de fonction)

+0

Je suppose que vous voulez dire "inférence de type" et non "interférence de type";) –

+0

Merci! après avoir regardé la réponse, cela prend tout son sens. Plusieurs réponses correctes mais la vôtre était la première et complète, donc vous obtenez une vérification. Merci à tout le monde! – Peter

3

Pourriez-vous définir pas comme un délégué distinct:

Func<T, string> func1 = t => t.ToString(); 
Func<T, bool> func2 = t => string.IsNullOrEmpty(func1(t)); 
2

Pour la première partie de la technique est connue sous le nom composition de fonction i.e. vous rédigez 2 fonctions pour créer une nouvelle fonction. Dans votre cas, vous avez une fonction Func<T,String> et une autre fonction (comme chaîne vide ou nulle) qui est de type Func<string,bool>, en utilisant la composition de fonctions, vous pouvez composer ces deux fonctions pour créer une nouvelle fonction du type Func<T,Bool>

langage de programmation le plus fonctionnel avoir cette composition de fonction déjà définie dans sa bibliothèque standard ou dans la langue elle-même. Mais il n'est pas difficile d'en créer un pour votre langue si le langage prend en charge les fonctions en tant que valeurs de première classe.

En C#, vous pouvez utiliser la fonction ci-dessous qui vous permettra de composer des fonctions:

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

1: Oui (Vous pouvez également paramétrer bool et string):

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

Pour 2 : Oui, mais vous devez compiler l'expression première:

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

.Compile compilera l'expression i nà une méthode CLR dynamique que vous pouvez appeler avec le délégué renvoyé.

Vous pouvez utiliser ce code comme ceci:

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

Par ailleurs, dans ce cas, vous devriez vraiment écrire une fonction d'ordre supérieur. Ce que vous faites ici (algébriquement) compose des monoides. Rappelez-vous function composition? f . g := f(g(x)) est ce que vous faites ici.

Pensez source que g:A->B et la carte comme f:B->C (où A, B et C sont des ensembles) de sorte que le résultat de f . g est h:A->C. En passant, l'opérateur . est souvent construit dans des langages de programmation fonctionnels, tels que Haskell et réalise la même chose que votre fonction compose (mais avec une syntaxe plus propre).