Ei kuvausta

Jordan Brown 828f366a7f Update doc-comment 9 vuotta sitten
.gitignore e2d202c512 Ignore entire Tup directory 10 vuotta sitten
ConstantValueMethodAttribute.cs ff20ed72b9 Add `Constant` method to inject constants 9 vuotta sitten
InvertVisitor.cs bf8cc63a48 Implement some missing expression types... 10 vuotta sitten
LICENSE 08e4f2da42 Initial commit 10 vuotta sitten
README.md 169fd31465 Of course I missed a name change :expressionless: 10 vuotta sitten
ReplaceVisitor.cs 116540d774 Change namespace 10 vuotta sitten
Tupfile aabe3a7476 Generate documentation during build 10 vuotta sitten
UnwrapVisitor.cs ff20ed72b9 Add `Constant` method to inject constants 9 vuotta sitten
UnwrappableMethod.cs 116540d774 Change namespace 10 vuotta sitten
Wax.cs 828f366a7f Update doc-comment 9 vuotta sitten

README.md

Wax

Wax grew out of my frustration with Linq-to-SQL's inability to handle InvocationExpressions, so its main purpose is to allow common expressions to be saved and re-used instead of repeated verbatim each time. Wax also contains a few other functions that I found useful when working with expressions.

using System;
using System.Linq.Expressions;
using ExpressionKit.Unwrap;

static class Example
{
  static Expression<Func<int, int>> Square = x => x * x;

  static Expression<Func<int, int>> SquSquare = Wax.Unwrap<int, int>(
    x => Square.Expand(Square.Expand(x)));

  static Expression<Func<int, int>> Cube = Wax.Unwrap<int, int>(
    x => SquSquare.Expand(x) / x);

  static Expression<Func<int, int>> Foo = Wax.Unwrap<int, int>(
    x => Cube.Expand(x + 1) * Square.Expand(x - 1));

  static void Main()
  {
    var expressions = new[]
    {
      Square,
      SquSquare,
      Cube,
      Foo
    };

    foreach (var expression in expressions)
      Console.WriteLine(expression);
  }
}
x => (x * x)
x => ((x * x) * (x * x))
x => (((x * x) * (x * x)) / x)
x => (((((x + 1) * (x + 1)) * ((x + 1) * (x + 1))) / (x + 1)) * ((x - 1) * (x - 1)))

Installation

To install Wax, run

Install-Package Wax

in your NuGet package manager console, or download the source and compile with

# Assuming Mono's C# compiler
mcs -o+ -t:library -out:Wax.dll *.cs

Then, in your code,

using ExpressionKit.Unwrap;

The Functions

Unwrap

This is the heart of Wax. It's used to unwrap other expressions into their definitions for you, so that Linq-to-SQL (or perhaps other frameworks that expect simple expressions) can digest them.

There are two variations of Unwrap: one for functions receiving a single argument, and another for functions receiving two arguments. In practice, I haven't needed more than this, but I may extend these to the full length offered by Func<T...> in the future.

Expressions are marked for unwrapping using Expand, which also has two variants.

Example:

using System;
using System.Linq;
using System.Linq.Expressions;
using ExpressionKit.Unwrap;

static class MyProgram
{
  static Expression<Func<MyModel, IQueryable<MyProperty>>>
    ModelProperties = /* some complex selection */;
    
  static void Main()
  {
    var red = MyContext.MyModels
      .Where(Wax.Unwrap<MyModel, bool>(m => ModelProperties
        .Expand(m)
        .Any(p => p.Color == Colors.Red)));
  }
}

Of course, having to explicitly state the type parameters for Unwrap every time can be irritating, and it is impossible when one of the type parameters refers to an anonymous type. Which is why Wax also provides...

UnwrappedWhere

This function is just Linq's Where combined with Unwrap to give you the convenience of type inference. Using UnwrappedWhere, our above example becomes:

using System;
using System.Linq;
using System.Linq.Expressions;
using ExpressionKit.Unwrap;

static class MyProgram
{
  static Expression<Func<MyModel, IQueryable<MyProperty>>>
    ModelProperties = /* some complex selection */;
    
  static void Main()
  {
    var red = MyContext.MyModels
      .UnwrappedWhere(m => ModelProperties
        .Expand(m)
        .Any(p => p.Color == Colors.Red)));
  }
}

UnwrappedSelect

This function is similar to UnwrappedWhere. You can probably guess what it does.

Or, And, Inverse

These three functions provide basic boolean logic for working with expressions. Their functionality doesn't extend far beyond what's offerred by Expression, but they are provided as extension methods, which I find easier to read.

Any, All

These two functions are just shorthand for combining lists of expressions with Or or And, respectively.

Expand

This function doesn't do much by itself; it's only used to flag which expressions to Unwrap. When actually evaluated, it will throw an InvalidOperationException.