diff --git a/Build/ExpressionReflect.nuspec b/Build/ExpressionReflect.nuspec index 2921c76..7fad4ff 100644 --- a/Build/ExpressionReflect.nuspec +++ b/Build/ExpressionReflect.nuspec @@ -22,8 +22,8 @@ - - - + + + diff --git a/README.md b/README.md index 9b9410c..b67532c 100644 --- a/README.md +++ b/README.md @@ -5,10 +5,10 @@ Why? ---- Provides the ability to "compile" expressions to delegates without using Reflection.Emit but only using reflection. -The created delegate will make use of reflection to execute the expression when it is invoked. This is much slower +The created delegate will make use of reflection to evaluate the expression when it is invoked. This is much slower than executing a compiled delegate of an expression! -This framework is intended to be used where dynamic code creation is not possible. The main purpose is the useage with +This framework is intended to be used where dynamic code creation is not possible. The main purpose is the usage with Xamarin.iOS due to it's restriction on Reflection.Emit. How? @@ -197,4 +197,7 @@ All this features can be combined to more complex expressions. Contributors ------------ -Bernhard Richter (seesharper) \ No newline at end of file +Bernhard Richter (seesharper) + + +Thank you! \ No newline at end of file diff --git a/Source/ExpressionReflect.Tests/BinaryOperatorTests.cs b/Source/ExpressionReflect.Tests/BinaryOperatorTests.cs index 0a62f65..c97db39 100644 --- a/Source/ExpressionReflect.Tests/BinaryOperatorTests.cs +++ b/Source/ExpressionReflect.Tests/BinaryOperatorTests.cs @@ -76,43 +76,43 @@ public void ShouldExecuteOperator_TypeIs() reflectionResult.Should().Be(emitResult); } - [Test] - public void ShouldExecuteOperator_Equals() - { - // Arrange - Expression> expression = s => s == "SomeValue"; - - // Act - Func emit = expression.Compile(); - Func reflection = expression.Reflect(); - - bool emitResult = emit.Invoke("SomeValue"); - bool reflectionResult = reflection.Invoke("SomeValue"); - - // Assert - emitResult.Should().BeTrue(); - reflectionResult.Should().BeTrue(); - reflectionResult.Should().Be(emitResult); - } - - [Test] - public void ShouldExecuteOperator_EqualsWithNullValue() - { - // Arrange - Expression> expression = s => s == null; - - // Act - Func emit = expression.Compile(); - Func reflection = expression.Reflect(); - - bool emitResult = emit.Invoke(null); - bool reflectionResult = reflection.Invoke(null); - - // Assert - emitResult.Should().BeTrue(); - reflectionResult.Should().BeTrue(); - reflectionResult.Should().Be(emitResult); - } + [Test] + public void ShouldExecuteOperator_Equals() + { + // Arrange + Expression> expression = s => s == "SomeValue"; + + // Act + Func emit = expression.Compile(); + Func reflection = expression.Reflect(); + + bool emitResult = emit.Invoke("SomeValue"); + bool reflectionResult = reflection.Invoke("SomeValue"); + + // Assert + emitResult.Should().BeTrue(); + reflectionResult.Should().BeTrue(); + reflectionResult.Should().Be(emitResult); + } + + [Test] + public void ShouldExecuteOperator_EqualsWithNullValue() + { + // Arrange + Expression> expression = s => s == null; + + // Act + Func emit = expression.Compile(); + Func reflection = expression.Reflect(); + + bool emitResult = emit.Invoke(null); + bool reflectionResult = reflection.Invoke(null); + + // Assert + emitResult.Should().BeTrue(); + reflectionResult.Should().BeTrue(); + reflectionResult.Should().Be(emitResult); + } } } diff --git a/Source/ExpressionReflect.Tests/EvaluatorTests.cs b/Source/ExpressionReflect.Tests/EvaluatorTests.cs index ddd2e19..afb2f3a 100644 --- a/Source/ExpressionReflect.Tests/EvaluatorTests.cs +++ b/Source/ExpressionReflect.Tests/EvaluatorTests.cs @@ -2,6 +2,9 @@ namespace ExpressionReflect.Tests { using System; + using System.Collections; + using System.Collections.Generic; + using System.Linq; using System.Linq.Expressions; using ExpressionReflect.Tests.Model; using FluentAssertions; @@ -35,10 +38,10 @@ public void ShouldPreEvaluate_LocalVariable() { // Arrange string str = "test"; - Expression> expresion = x => x.Firstname == str; + Expression> expression = x => x.Firstname == str; // Act - string expressionString = expresion.PartialEval().ToString(); + string expressionString = expression.PartialEval().ToString(); Console.WriteLine(expressionString); // Assert @@ -50,10 +53,10 @@ public void ShouldPreEvaluate_LocalFuncWithoutParameter() { // Arrange Func func = () => "test"; - Expression> expresion = x => x.Firstname == func(); + Expression> expression = x => x.Firstname == func(); // Act - string expressionString = expresion.PartialEval().ToString(); + string expressionString = expression.PartialEval().ToString(); Console.WriteLine(expressionString); // Assert @@ -65,10 +68,10 @@ public void ShouldPreEvaluate_LocalFuncWithConstantParameter() { // Arrange Func func = x => "test" + x; - Expression> expresion = x => x.Firstname == func(5); + Expression> expression = x => x.Firstname == func(5); // Act - string expressionString = expresion.PartialEval().ToString(); + string expressionString = expression.PartialEval().ToString(); Console.WriteLine(expressionString); // Assert @@ -81,10 +84,10 @@ public void ShouldPreEvaluate_LocalFuncWithLocalVariableParameter() // Arrange Func func = x => "test" + x; int i = 5; - Expression> expresion = x => x.Firstname == func(i); + Expression> expression = x => x.Firstname == func(i); // Act - string expressionString = expresion.PartialEval().ToString(); + string expressionString = expression.PartialEval().ToString(); Console.WriteLine(expressionString); // Assert @@ -97,10 +100,10 @@ public void ShouldPreEvaluate_LocalFuncWithLocalFuncParameter() // Arrange Func func = x => "test" + x; Func i = () => 5; - Expression> expresion = x => x.Firstname == func(i()); + Expression> expression = x => x.Firstname == func(i()); // Act - string expressionString = expresion.PartialEval().ToString(); + string expressionString = expression.PartialEval().ToString(); Console.WriteLine(expressionString); // Assert @@ -111,10 +114,10 @@ public void ShouldPreEvaluate_LocalFuncWithLocalFuncParameter() public void ShouldPreEvaluate_InstanceMethodCallWithoutParameter() { // Arrange - Expression> expresion = x => x.Firstname == this.GetString(); + Expression> expression = x => x.Firstname == this.GetString(); // Act - string expressionString = expresion.PartialEval().ToString(); + string expressionString = expression.PartialEval().ToString(); Console.WriteLine(expressionString); // Assert @@ -125,10 +128,10 @@ public void ShouldPreEvaluate_InstanceMethodCallWithoutParameter() public void ShouldPreEvaluate_StaticMethodCallWithoutParameter() { // Arrange - Expression> expresion = x => x.Firstname == GetStringStatic(); + Expression> expression = x => x.Firstname == GetStringStatic(); // Act - string expressionString = expresion.PartialEval().ToString(); + string expressionString = expression.PartialEval().ToString(); Console.WriteLine(expressionString); // Assert @@ -139,10 +142,10 @@ public void ShouldPreEvaluate_StaticMethodCallWithoutParameter() public void ShouldPreEvaluate_InstanceMethodCallWithConstantParameter() { // Arrange - Expression> expresion = x => x.Firstname == this.GetString(5); + Expression> expression = x => x.Firstname == this.GetString(5); // Act - string expressionString = expresion.PartialEval().ToString(); + string expressionString = expression.PartialEval().ToString(); Console.WriteLine(expressionString); // Assert @@ -153,10 +156,10 @@ public void ShouldPreEvaluate_InstanceMethodCallWithConstantParameter() public void ShouldPreEvaluate_StaticMethodCallWithConstantParameter() { // Arrange - Expression> expresion = x => x.Firstname == GetStringStatic(5); + Expression> expression = x => x.Firstname == GetStringStatic(5); // Act - string expressionString = expresion.PartialEval().ToString(); + string expressionString = expression.PartialEval().ToString(); Console.WriteLine(expressionString); // Assert @@ -168,10 +171,10 @@ public void ShouldPreEvaluate_InstanceMethodCallWithLocalVariableParameter() { // Arrange int i = 5; - Expression> expresion = x => x.Firstname == this.GetString(i); + Expression> expression = x => x.Firstname == this.GetString(i); // Act - string expressionString = expresion.PartialEval().ToString(); + string expressionString = expression.PartialEval().ToString(); Console.WriteLine(expressionString); // Assert @@ -183,10 +186,10 @@ public void ShouldPreEvaluate_StaticMethodCallWithLocalVariableParameter() { // Arrange int i = 5; - Expression> expresion = x => x.Firstname == GetStringStatic(i); + Expression> expression = x => x.Firstname == GetStringStatic(i); // Act - string expressionString = expresion.PartialEval().ToString(); + string expressionString = expression.PartialEval().ToString(); Console.WriteLine(expressionString); // Assert @@ -198,10 +201,10 @@ public void ShouldPreEvaluate_InstanceMethodCallWithLocalFuncParameter() { // Arrange Func i = () => 5; - Expression> expresion = x => x.Firstname == this.GetString(i()); + Expression> expression = x => x.Firstname == this.GetString(i()); // Act - string expressionString = expresion.PartialEval().ToString(); + string expressionString = expression.PartialEval().ToString(); Console.WriteLine(expressionString); // Assert @@ -213,29 +216,46 @@ public void ShouldPreEvaluate_StaticMethodCallWithLocalFuncParameter() { // Arrange Func i = () => 5; - Expression> expresion = x => x.Firstname == GetStringStatic(i()); + Expression> expression = x => x.Firstname == GetStringStatic(i()); // Act - string expressionString = expresion.PartialEval().ToString(); + string expressionString = expression.PartialEval().ToString(); Console.WriteLine(expressionString); // Assert expressionString.Should().Be(@"x => (x.Firstname == ""test5"")"); } + //[Test] + //public void ShouldPreEvaluate_LocalFuncWithLambdaParameterParameter() + //{ + // // Arrange + // Func func = x => x; + // Expression> expression = x => x.Firstname == func(x.Lastname); + + // // Act + // string expressionString = expression.PartialEval().ToString(); + // Console.WriteLine(expressionString); + + // // Assert + // expressionString.Should().Be(@"x => (x.Firstname == func(x.Lastname))"); + //} + [Test] - public void ShouldPreEvaluate_LocalFuncWithLambdaParameterParameter() + public void ShouldPreEvaluate_LocalCollectionContains() { // Arrange - Func func = x => x; - Expression> expresion = x => x.Firstname == func(x.Lastname); + var ids = new List { 4, 5, 7 }; + Expression> expression = x => ids.Contains(x.Age); // Act - string expressionString = expresion.PartialEval().ToString(); + Expression exp = expression.PartialEval(); + exp = exp.ExpandCollection(); + string expressionString = exp.ToString(); Console.WriteLine(expressionString); // Assert - expressionString.Should().Be(@"x => (x.Firstname == func(x.Lastname))"); + expressionString.Should().Be(@"x => {4|5|7}.Contains(x.Age)"); } } } diff --git a/Source/ExpressionReflect.Tests/ExpressionReflect.Tests.csproj b/Source/ExpressionReflect.Tests/ExpressionReflect.Tests.csproj index cc68cb3..0fcab5d 100644 --- a/Source/ExpressionReflect.Tests/ExpressionReflect.Tests.csproj +++ b/Source/ExpressionReflect.Tests/ExpressionReflect.Tests.csproj @@ -9,10 +9,11 @@ Properties ExpressionReflect.Tests ExpressionReflect.Tests - v4.5 + v4.5.1 512 ..\ true + true @@ -32,12 +33,6 @@ 4 - - ..\packages\FluentAssertions.2.0.1\lib\net45\FluentAssertions.dll - - - ..\packages\NUnit.2.6.2\lib\nunit.framework.dll - @@ -45,6 +40,15 @@ + + ..\packages\NUnit.2.6.3\lib\nunit.framework.dll + + + ..\packages\FluentAssertions.3.2.1\lib\net45\FluentAssertions.Core.dll + + + ..\packages\FluentAssertions.3.2.1\lib\net45\FluentAssertions.dll + @@ -67,7 +71,7 @@ - {320289ae-b78b-4c5a-b52e-08f81ae7f2ed} + {320289AE-B78B-4C5A-B52E-08F81AE7F2ED} ExpressionReflect diff --git a/Source/ExpressionReflect.Tests/FuncExecutionTests.cs b/Source/ExpressionReflect.Tests/FuncExecutionTests.cs index eba06a4..7e215da 100644 --- a/Source/ExpressionReflect.Tests/FuncExecutionTests.cs +++ b/Source/ExpressionReflect.Tests/FuncExecutionTests.cs @@ -54,41 +54,41 @@ public void ShouldCreateSimpleFunc_PropertyGetter() reflectionResult.Should().Be(emitResult); } - [Test] - public void ShouldCreateSimpleFunc_StaticPropertyGetter() - { - //Arrange - Expression> expression = () => Customer.StaticProperty; - - //Act - Func emit = expression.Compile(); - Func reflection = expression.Reflect(); - - string emitResult = emit.Invoke(); - string reflectionResult = reflection.Invoke(); - - //Assert - emitResult.Should().Be("StaticProperty"); - reflectionResult.Should().Be("StaticProperty"); - } - - [Test] - public void ShouldCreateSimpleFunc_StaticField() - { - //Arrange - Expression> expression = () => Customer.StaticField; - - //Act - Func emit = expression.Compile(); - Func reflection = expression.Reflect(); - - string emitResult = emit.Invoke(); - string reflectionResult = reflection.Invoke(); - - //Assert - emitResult.Should().Be("StaticField"); - reflectionResult.Should().Be("StaticField"); - } + [Test] + public void ShouldCreateSimpleFunc_StaticPropertyGetter() + { + //Arrange + Expression> expression = () => Customer.StaticProperty; + + //Act + Func emit = expression.Compile(); + Func reflection = expression.Reflect(); + + string emitResult = emit.Invoke(); + string reflectionResult = reflection.Invoke(); + + //Assert + emitResult.Should().Be("StaticProperty"); + reflectionResult.Should().Be("StaticProperty"); + } + + [Test] + public void ShouldCreateSimpleFunc_StaticField() + { + //Arrange + Expression> expression = () => Customer.StaticField; + + //Act + Func emit = expression.Compile(); + Func reflection = expression.Reflect(); + + string emitResult = emit.Invoke(); + string reflectionResult = reflection.Invoke(); + + //Assert + emitResult.Should().Be("StaticField"); + reflectionResult.Should().Be("StaticField"); + } [Test] public void ShouldCreateSimpleFunc_PropertyGetter_MethodCall() diff --git a/Source/ExpressionReflect.Tests/packages.config b/Source/ExpressionReflect.Tests/packages.config index 9ac2dd5..446314d 100644 --- a/Source/ExpressionReflect.Tests/packages.config +++ b/Source/ExpressionReflect.Tests/packages.config @@ -1,5 +1,5 @@  - - + + \ No newline at end of file diff --git a/Source/ExpressionReflect/ActionExtensions.cs b/Source/ExpressionReflect/ActionExtensions.cs index e95d113..c94a646 100644 --- a/Source/ExpressionReflect/ActionExtensions.cs +++ b/Source/ExpressionReflect/ActionExtensions.cs @@ -34,5 +34,77 @@ public static Action Reflect(this Expression action = (a, b, c, d) => target.Execute(a, b, c, d); return action; } + + public static Action Reflect(this Expression> target) + { + Action action = (a, b, c, d, e) => target.Execute(a, b, c, d, e); + return action; + } + + public static Action Reflect(this Expression> target) + { + Action action = (a, b, c, d, e, f) => target.Execute(a, b, c, d, e, f); + return action; + } + + public static Action Reflect(this Expression> target) + { + Action action = (a, b, c, d, e, f, g) => target.Execute(a, b, c, d, e, f, g); + return action; + } + + public static Action Reflect(this Expression> target) + { + Action action = (a, b, c, d, e, f, g, h) => target.Execute(a, b, c, d, e, f, g, h); + return action; + } + + public static Action Reflect(this Expression> target) + { + Action action = (a, b, c, d, e, f, g, h, i) => target.Execute(a, b, c, d, e, f, g, h, i); + return action; + } + + public static Action Reflect(this Expression> target) + { + Action action = (a, b, c, d, e, f, g, h, i, j) => target.Execute(a, b, c, d, e, f, g, h, i, j); + return action; + } + + public static Action Reflect(this Expression> target) + { + Action action = (a, b, c, d, e, f, g, h, i, j, k) => target.Execute(a, b, c, d, e, f, g, h, i, j, k); + return action; + } + + public static Action Reflect(this Expression> target) + { + Action action = (a, b, c, d, e, f, g, h, i, j, k, l) => target.Execute(a, b, c, d, e, f, g, h, i, j, k, l); + return action; + } + + public static Action Reflect(this Expression> target) + { + Action action = (a, b, c, d, e, f, g, h, i, j, k, l, m) => target.Execute(a, b, c, d, e, f, g, h, i, j, k, l, m); + return action; + } + + public static Action Reflect(this Expression> target) + { + Action action = (a, b, c, d, e, f, g, h, i, j, k, l, m, n) => target.Execute(a, b, c, d, e, f, g, h, i, j, k, l, m, n); + return action; + } + + public static Action Reflect(this Expression> target) + { + Action action = (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => target.Execute(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o); + return action; + } + + public static Action Reflect(this Expression> target) + { + Action action = (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => target.Execute(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p); + return action; + } } } \ No newline at end of file diff --git a/Source/ExpressionReflect/Evaluator.cs b/Source/ExpressionReflect/Evaluator.cs index 9cd7886..1811d5c 100644 --- a/Source/ExpressionReflect/Evaluator.cs +++ b/Source/ExpressionReflect/Evaluator.cs @@ -8,12 +8,12 @@ /// Enables the partial evaluation of queries. /// /// - /// From http://msdn.microsoft.com/en-us/library/bb546158.aspx + /// From http://blogs.msdn.com/b/mattwar/archive/2007/08/01/linq-building-an-iqueryable-provider-part-iii.aspx /// - public static class Evaluator + internal static class Evaluator { /// - /// Performs evaluation & replacement of independent sub-trees + /// Performs evaluation and replacement of independent sub-trees. /// /// The root of the expression tree. /// A new tree with sub-trees evaluated and replaced. @@ -23,7 +23,7 @@ public static Expression PartialEval(this Expression expression) } /// - /// Performs evaluation & replacement of independent sub-trees + /// Performs evaluation and replacement of independent sub-trees. /// /// The root of the expression tree. /// A function that decides whether a given expression node can be part of the local function. @@ -39,7 +39,7 @@ private static bool CanBeEvaluatedLocally(Expression expression) } /// - /// Evaluates & replaces sub-trees when first candidate is reached (top-down) + /// Evaluates and replaces sub-trees when first candidate is reached (top-down). /// private class SubtreeEvaluator : ExpressionVisitor { @@ -57,11 +57,11 @@ internal Expression Eval(Expression exp) public override Expression Visit(Expression exp) { - if (exp == null) + if(exp == null) { return null; } - if (this.candidates.ContainsKey(exp)) + if(this.candidates.ContainsKey(exp)) { return this.Evaluate(exp); } @@ -70,11 +70,12 @@ public override Expression Visit(Expression exp) private Expression Evaluate(Expression e) { - if (e.NodeType == ExpressionType.Constant) + if(e.NodeType == ExpressionType.Constant) { return e; } + // Note[mge]: Uses the expression evaluation instead of Expression.Compile(). LambdaExpression lambda = Expression.Lambda(e); object value = lambda.Execute(); return Expression.Constant(value, e.Type); @@ -105,14 +106,14 @@ internal IDictionary Nominate(Expression expression) public override Expression Visit(Expression expression) { - if (expression != null) + if(expression != null) { bool saveCannotBeEvaluated = this.cannotBeEvaluated; this.cannotBeEvaluated = false; base.Visit(expression); - if (!this.cannotBeEvaluated) + if(!this.cannotBeEvaluated) { - if (this.fnCanBeEvaluated(expression) && !this.candidates.ContainsKey(expression)) + if(this.fnCanBeEvaluated(expression) && !this.candidates.ContainsKey(expression)) { this.candidates.Add(expression, expression); } diff --git a/Source/ExpressionReflect/ExpressionExtensions.cs b/Source/ExpressionReflect/ExpressionExtensions.cs index 9cddee5..0168fb2 100644 --- a/Source/ExpressionReflect/ExpressionExtensions.cs +++ b/Source/ExpressionReflect/ExpressionExtensions.cs @@ -10,5 +10,10 @@ public static object Execute(this Expression expression, params object[] values) object result = visitor.Execute(values); return result; } + + public static TResult Execute(this Expression expression, params object[] values) + { + return (TResult)expression.Execute(values); + } } } \ No newline at end of file diff --git a/Source/ExpressionReflect/ExpressionReflect.csproj b/Source/ExpressionReflect/ExpressionReflect.csproj index 0f6a0f5..543ab1c 100644 --- a/Source/ExpressionReflect/ExpressionReflect.csproj +++ b/Source/ExpressionReflect/ExpressionReflect.csproj @@ -11,7 +11,7 @@ ExpressionReflect ExpressionReflect v4.0 - Profile154 + Profile344 512 {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} @@ -38,9 +38,6 @@ 4 bin\Release\ExpressionReflect.xml - - true - ..\..\ExpressionReflect.snk @@ -53,17 +50,13 @@ + + - - - ExpressionReflect.snk - - -