A modern C# metaprogramming library.
The C# language currently is not completely able to automatically infer the return type of anonymous methods when using a var
declaration or when returning curried functions. The helper methods in the ZySharp.Metaprogramming.Lambda
class can be used to work around this limitation.
// Expression<Func<>>
var e = Lambda.Expr((int x) => x == 42);
var e = Lambda.Expr((int x) => new { Value = x });
var e = Lambda.Expr((int x) => Lambda.Func((int y) => x + y));
// Func<>
var d = Lambda.Func((int x) => x == 42)
var d = Lambda.Func((int x) => new { Value = x });
var d = Lambda.Func((int x) => Lambda.Func((int y) => x + y));
When creating dynamic LINQ expressions, it is often useful to use foreign lambda expressions inside an outer expression. While this is somewhat possible (.Compile().Invoke(...)
), most third-party libraries (e.g. LINQ to Entities
) are not able to understand the resulting expression tree. The ZySharp.Metaprogramming.Expr
class provides a set of simple functions to solve this problem.
// Expression<Func<>>
var inner = Lambda.Expr((int x) => x == 42);
var outer = Lambda.Expr((IQueryable<int> x) => x.Where(inner));
// :. Expression<Func<int, bool>>
var result = outer.Expand(); // x => x.Where(x => x == 42)
// Func<>
var inner = Lambda.Expr((int x) => x == 42);
var outer = Lambda.Expr((IEnumerable<int> x) => x.Where(inner.Compile()));
// :. Func<int, bool>
var result = outer.Expand(); // x => x.Where(x => x == 42)
var lower = Lambda.Expr((int x) => x >= 10);
var upper = Lambda.Expr((int x) => x <= 42);
var outer = Lambda.Expr((IQueryable<int> x) => x.Where(x => lower.Invoke(x) && upper.Invoke(x)));
var result = outer.Expand(); // x => x.Where(x => x >= 10 && x <= 42)
In the following example, GetPredicateExpressionWithParam()
is evaluated at runtime (when .Expand()
is called). The resulting expression is then integrated into the outer expression tree. During this process, all captured variables (num42
) are also evaluated.
private static Expression<Func<int, bool>> GetPredicateExpressionWithParam(int number)
{
return x => x == number;
}
var num42 = 42;
var outer = Lambda.Expr((IQueryable<int> x) => x.Where(x => GetPredicateExpressionWithParam(num42).Invoke(x)));
var result = outer.Expand(); // x => x.Where(x => x == 42)
By default, expression trees can only be compared by reference. To be able to e.g. store semantically equivalent expression trees in a dictionary, the ZySharp.Metaprogramming.ExprEqualityComparer
implements the IEqualityComparer<T>
interface for the Expression
class.
var x = Lambda.Expr((int a, int b) => a + b);
var y = Lambda.Expr((int c, int d) => c + d);
ExprEqualityComparer.Default.Equals(x, y); // true
var z = Lambda.Expr((int a, int b) => a + a);
ExprEqualityComparer.Default.Equals(x, z); // false
All built-in Expression
types except DynamicExpression
are supported.
Versions follow the semantic versioning scheme.
ZySharp.Metaprogramming is licensed under the MIT license.