Note that there are some explanatory texts on larger screens.

plurals
  1. POHow do I compose Linq Expressions? ie Func<Exp<Func<X, Y>>, Exp<Func<Y, Z>>, Exp<Func<X, Z>>>
    text
    copied!<p>I'm creating a <code>Validator&lt;T&gt;</code> class. I'm attempting to implement the Linq <code>SelectMany</code> extension methods for my validator to be able to compose expressions using a Linq query and validate the final result even when the underlying values change.</p> <p>The following test code demonstrates my intent.</p> <pre><code>var a = 2; var b = 3; var va = Validator.Create(() =&gt; a, n =&gt; n &gt;= 0 &amp;&amp; n &lt; 5); var vb = Validator.Create(() =&gt; b, n =&gt; n &gt;= 0 &amp;&amp; n &lt; 5); var vc = from ia in va from ib in vb select ia + ib; Debug.Assert(vc.Value == a + b); //2 + 3 Debug.Assert(vc.Value == 5); Debug.Assert(vc.IsValid == true); a = 7; Debug.Assert(vc.Value == a + b); //7 + 3 Debug.Assert(vc.Value == 10); Debug.Assert(va.IsValid == false); Debug.Assert(vb.IsValid == true); Debug.Assert(vc.IsValid == false); </code></pre> <p>I've seen the following question <a href="https://stackoverflow.com/questions/53597/how-do-i-compose-existing-linq-expressions">How do I compose existing Linq Expressions</a> which shows me how to compose two <code>Func&lt;T, bool&gt;</code>'s together using an <code>And</code> expression, but I need to be able to compose functions together in a more, well, functional way.</p> <p>I have, for example, the following two expressions:</p> <pre><code>public Expression&lt;Func&lt;T&gt;&gt; ValueExpression { get; private set; } public Expression&lt;Func&lt;T, bool&gt;&gt; ValidationExpression { get; private set; } </code></pre> <p>I wish to create a new expression like this:</p> <pre><code> public Expression&lt;Func&lt;bool&gt;&gt; IsValidExpression { get { // TODO: Compose expressions rather than compile &amp; invoke. } } </code></pre> <p>More succinctly I'm trying to create these functions:</p> <pre><code>// Specific case Func&lt;Expression&lt;Func&lt;T&gt;&gt;, Expression&lt;Func&lt;T, bool&gt;&gt;, Expression&lt;Func&lt;bool&gt;&gt;&gt; // General case Func&lt;Expression&lt;Func&lt;X, Y&gt;&gt;, Expression&lt;Func&lt;Y, Z&gt;&gt;, Expression&lt;Func&lt;X, Z&gt;&gt;&gt; </code></pre> <p>The general case function can be modified to accept different numbers of generic arguments as needed to compose any function.</p> <p>I've searched Stack Overflow (of course) and the web, but haven't an example that solves this issue.</p> <p>My code for the <code>Validator&lt;T&gt;</code> class is below.</p> <pre><code>public class Validator&lt;T&gt; { public Validator(Expression&lt;Func&lt;T&gt;&gt; valueFunc, Expression&lt;Func&lt;T, bool&gt;&gt; validationFunc) { this.ValueExpression = valueFunc; this.ValidationExpression = validationFunc; } public Expression&lt;Func&lt;T&gt;&gt; ValueExpression { get; private set; } public Expression&lt;Func&lt;T, bool&gt;&gt; ValidationExpression { get; private set; } public T Value { get { return this.ValueExpression.Compile().Invoke(); } } public bool IsValid { get { return this.IsValidExpression.Compile().Invoke(); } } public Expression&lt;Func&lt;bool&gt;&gt; IsValidExpression { get { // TODO: Compose expressions. } } } </code></pre> <p>My <code>SelectMany</code> extensions contain loads of yucky <code>.Compile().Invoke()</code> which I want to get rid of.</p> <pre><code>public static Validator&lt;U&gt; SelectMany&lt;T, U&gt;(this Validator&lt;T&gt; @this, Expression&lt;Func&lt;T, Validator&lt;U&gt;&gt;&gt; k) { Expression&lt;Func&lt;T&gt;&gt; fvtv = @this.ValueExpression; Expression&lt;Func&lt;Validator&lt;U&gt;&gt;&gt; fvu = () =&gt; k.Compile().Invoke(fvtv.Compile().Invoke()); Expression&lt;Func&lt;U&gt;&gt; fvuv = fvu.Compile().Invoke().ValueExpression; Expression&lt;Func&lt;U, bool&gt;&gt; fvtiv = u =&gt; @this.ValidationExpression.Compile().Invoke(fvtv.Compile().Invoke()); return fvuv.ToValidator(fvtiv); } public static Validator&lt;V&gt; SelectMany&lt;T, U, V&gt;(this Validator&lt;T&gt; @this, Expression&lt;Func&lt;T, Validator&lt;U&gt;&gt;&gt; k, Expression&lt;Func&lt;T, U, V&gt;&gt; s) { Expression&lt;Func&lt;Validator&lt;U&gt;&gt;&gt; fvu = () =&gt; @this.SelectMany(k); Expression&lt;Func&lt;T&gt;&gt; fvtv = @this.ValueExpression; Expression&lt;Func&lt;U&gt;&gt; fvuv = fvu.Compile().Invoke().ValueExpression; Expression&lt;Func&lt;T, bool&gt;&gt; fvtiv = @this.ValidationExpression; Expression&lt;Func&lt;U, bool&gt;&gt; fvuiv = u =&gt; fvu.Compile().Invoke().ValidationExpression.Compile().Invoke(u); Expression&lt;Func&lt;V&gt;&gt; fvv = () =&gt; s.Compile().Invoke(fvtv.Compile().Invoke(), fvuv.Compile().Invoke()); Expression&lt;Func&lt;V, bool&gt;&gt; fvviv = v =&gt; fvtiv.Compile().Invoke(fvtv.Compile().Invoke()) &amp;&amp; fvuiv.Compile().Invoke(fvuv.Compile().Invoke()); return fvv.ToValidator(fvviv); } </code></pre> <p>Thanks in advance!</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload