-
Notifications
You must be signed in to change notification settings - Fork 934
Avoid lambda compilation as much as possible #2957
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
bahusoid
merged 16 commits into
nhibernate:master
from
gokhanabatay:AvoidLambdaCompilation
Dec 14, 2021
Merged
Changes from 4 commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
bb1bf45
Merge pull request #33 from nhibernate/master
gokhanabatay f1586a9
Avoid lambda compilation as much as possible, concurrent Compile() ca…
043df3c
convert expression avoid as much as cast if its possible
cbb0b5c
convert method call parameter fix
5c8ad16
Add runtime shim for LambdaExpression.Compile(bool)
hazzik 9c6808c
Update src/NHibernate/Impl/ExpressionProcessor.cs
gokhanabatay 32d674d
Some refactoring. No functional changes
bahusoid ea946ea
Revert "Add runtime shim for LambdaExpression.Compile(bool)" - it's n…
bahusoid af8212e
Fixed compiling of int? -> int due my last refactoring
bahusoid 4ee6a7f
whitespaces
bahusoid fcb1ecb
Refactor getObj to be more generic
hazzik caf970c
Add tests for int to long? and decimal?
hazzik 4d29727
Add tests to upcast nullable int? -> long?
hazzik 9c7a726
test case expression double compile issue fixed
0a83347
Whitespaces
hazzik 5cc5214
Add more tests
hazzik File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
243 changes: 243 additions & 0 deletions
243
src/NHibernate.Test/Criteria/Lambda/ExpressionProcessorFindValueFixture.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,243 @@ | ||
using System; | ||
using System.Linq.Expressions; | ||
using System.Reflection; | ||
using NHibernate.Impl; | ||
using NUnit.Framework; | ||
using Expression = System.Linq.Expressions.Expression; | ||
|
||
namespace NHibernate.Test.Criteria.Lambda | ||
{ | ||
public static class DateTimeExtensions | ||
{ | ||
public static long ToLongDateTime(this DateTime date) | ||
{ | ||
return Convert.ToInt64(date.ToString("yyyyMMddHHmmss")); | ||
} | ||
} | ||
|
||
[TestFixture] | ||
public class ExpressionProcessorFindValueFixture | ||
{ | ||
private static object GetValue<T>(Expression<Func<T>> expression) | ||
{ | ||
try | ||
{ | ||
return ExpressionProcessor.FindValue(expression.Body); | ||
} | ||
catch (TargetInvocationException e) | ||
{ | ||
throw e.InnerException; | ||
} | ||
} | ||
|
||
private static int GetIntegerDate() | ||
{ | ||
return Convert.ToInt32(DateTime.Now.ToString("yyyyMMdd")); | ||
} | ||
|
||
[Test] | ||
public void GivenStaticPropertyInstanceMethodCall() | ||
{ | ||
var actual = GetValue(() => DateTime.Now.ToString("yyyyMMdd")); | ||
var expected = DateTime.Now.ToString("yyyyMMdd"); | ||
|
||
Assert.AreEqual(expected, actual); | ||
} | ||
|
||
[Test] | ||
public void GivenStaticPropertyInstanceMultipleMethodCall() | ||
{ | ||
var actual = GetValue(() => DateTime.Now.AddDays(365).ToString("yyyyMMdd")); | ||
var expected = DateTime.Now.AddDays(365).ToString("yyyyMMdd"); | ||
|
||
Assert.AreEqual(expected, actual); | ||
} | ||
|
||
[Test] | ||
public void GivenStaticPropertyInstanceMethodCallThenCast() | ||
{ | ||
var actual = GetValue(() => Convert.ToInt32(DateTime.Now.AddDays(365).ToString("yyyyMMdd"))); | ||
var expected = Convert.ToInt32(DateTime.Now.AddDays(365).ToString("yyyyMMdd")); | ||
|
||
Assert.AreEqual(expected, actual); | ||
} | ||
|
||
[Test] | ||
public void GivenStaticMethodCall() | ||
{ | ||
var actual = GetValue(() => GetIntegerDate()); | ||
var expected = GetIntegerDate(); | ||
|
||
Assert.AreEqual(expected, actual); | ||
} | ||
|
||
[Test] | ||
public void GivenExtensionMethodCall() | ||
{ | ||
var date = DateTime.Now; | ||
var actual = GetValue(() => date.ToLongDateTime()); | ||
var expected = date.ToLongDateTime(); | ||
|
||
Assert.AreEqual(expected, actual); | ||
} | ||
|
||
[Test] | ||
public void GivenNestedPropertyAccess() | ||
{ | ||
var animal = new { Snake = new { Animal = new { Name = "Scorpion" } } }; | ||
var actual = GetValue(() => animal.Snake.Animal.Name); | ||
var expected = animal.Snake.Animal.Name; | ||
|
||
Assert.AreEqual(expected, actual); | ||
} | ||
|
||
[Test] | ||
public void GivenGuidToStringCast() | ||
{ | ||
var guid = Guid.NewGuid(); | ||
Expression<Func<string>> expression = () => $"{guid}"; | ||
var actual = GetValue(expression); | ||
|
||
//Check with expression compile and invoke | ||
var lambdaExpression = Expression.Lambda(expression).Compile(); | ||
var expected = ((dynamic) lambdaExpression.DynamicInvoke()).Invoke(); | ||
|
||
Assert.AreEqual(expected, actual); | ||
} | ||
|
||
[Test] | ||
public void GivenNestedPropertyToIntegerCast() | ||
{ | ||
var animal = new { Snake = new { Animal = new { Weight = 9.89 } } }; | ||
Expression<Func<int>> expression = () => (int) animal.Snake.Animal.Weight; | ||
var actual = GetValue(expression); | ||
|
||
//Check with expression compile and invoke | ||
var lambdaExpression = Expression.Lambda(expression).Compile(); | ||
var expected = ((dynamic) lambdaExpression.DynamicInvoke()).Invoke(); | ||
|
||
Assert.AreEqual(expected, actual); | ||
} | ||
|
||
[Test] | ||
public void GivenNestedPropertyToIntegerConvert() | ||
{ | ||
var animal = new { Snake = new { Animal = new { Weight = 9.89 } } }; | ||
Expression<Func<int>> expression = () => Convert.ToInt32(animal.Snake.Animal.Weight); | ||
var actual = GetValue(expression); | ||
|
||
//Check with expression compile and invoke | ||
var lambdaExpression = Expression.Lambda(expression).Compile(); | ||
var expected = ((dynamic) lambdaExpression.DynamicInvoke()).Invoke(); | ||
|
||
Assert.AreEqual(expected, actual); | ||
} | ||
|
||
[Test] | ||
public void GivenNullToIntegerCastFails() | ||
{ | ||
object value = null; | ||
Expression<Func<int>> expression = () => (int) value; | ||
|
||
Assert.Throws<NullReferenceException>(() => GetValue(expression)); | ||
|
||
//Check with expression compile and invoke | ||
var lambdaExpression = Expression.Lambda(expression).Compile(); | ||
|
||
Assert.Throws<NullReferenceException>(() => ((dynamic) lambdaExpression.DynamicInvoke()).Invoke()); | ||
} | ||
|
||
[Test] | ||
public void GivenNullableIntegerToIntegerCastFails() | ||
{ | ||
int? value = null; | ||
Expression<Func<int>> expression = () => (int) value; | ||
|
||
Assert.Throws<InvalidOperationException>(() => GetValue(expression)); | ||
|
||
//Check with expression compile and invoke | ||
var lambdaExpression = Expression.Lambda(expression).Compile(); | ||
|
||
Assert.Throws<InvalidOperationException>(() => ((dynamic) lambdaExpression.DynamicInvoke()).Invoke()); | ||
|
||
} | ||
|
||
[Test] | ||
public void GivenIntegerToNullableIntegerCast() | ||
{ | ||
int value = 12345; | ||
Expression<Func<int?>> expression = () => value; | ||
|
||
var actual = GetValue(expression); | ||
|
||
//Check with expression compile and invoke | ||
var lambdaExpression = Expression.Lambda(expression).Compile(); | ||
|
||
var expected = ((dynamic) lambdaExpression.DynamicInvoke()).Invoke(); | ||
|
||
Assert.AreEqual(expected, actual); | ||
|
||
} | ||
|
||
[Test] | ||
public void GivenInt16ToIntegerCast() | ||
{ | ||
short value = 12345; | ||
Expression<Func<int>> expression = () => value; | ||
|
||
var actual = GetValue(expression); | ||
|
||
//Check with expression compile and invoke | ||
var lambdaExpression = Expression.Lambda(expression).Compile(); | ||
|
||
var expected = ((dynamic) lambdaExpression.DynamicInvoke()).Invoke(); | ||
|
||
Assert.AreEqual(expected, actual); | ||
|
||
} | ||
|
||
[Test] | ||
public void GivenNullableDecimalToDecimalCast() | ||
{ | ||
decimal? value = 9.89m; | ||
Expression<Func<decimal>> expression = () => (decimal) value; | ||
|
||
var actual = GetValue(expression); | ||
|
||
//Check with expression compile and invoke | ||
var lambdaExpression = Expression.Lambda(expression).Compile(); | ||
var expected = ((dynamic) lambdaExpression.DynamicInvoke()).Invoke(); | ||
|
||
Assert.AreEqual(expected, actual); | ||
|
||
} | ||
|
||
[Test] | ||
public void GivenStringToIntegerCastFails() | ||
{ | ||
object value = "Abatay"; | ||
Expression<Func<int>> expression = () => (int) value; | ||
|
||
Assert.Throws<InvalidCastException>(() => GetValue(expression)); | ||
|
||
//Check with expression compile and invoke | ||
var lambdaExpression = Expression.Lambda(expression).Compile(); | ||
|
||
Assert.Throws<InvalidCastException>(() => ((dynamic) lambdaExpression.DynamicInvoke()).Invoke()); | ||
} | ||
|
||
[Test] | ||
public void GivenBooleanToCharCastFails() | ||
{ | ||
object isTrue = true; | ||
Expression<Func<char>> expression = () => (char) isTrue; | ||
|
||
Assert.Throws<InvalidCastException>(() => GetValue(expression)); | ||
|
||
//Check with expression compile and invoke | ||
var lambdaExpression = Expression.Lambda(expression).Compile(); | ||
|
||
Assert.Throws<InvalidCastException>(() => ((dynamic) lambdaExpression.DynamicInvoke()).Invoke()); | ||
} | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
using System; | ||
using System.Linq.Expressions; | ||
|
||
namespace NHibernate.Impl | ||
{ | ||
#if NET461 | ||
internal static class LambdaExpressionExtensions | ||
{ | ||
public static Delegate Compile(this LambdaExpression expression, bool preferInterpretation) => | ||
expression.Compile(); //Concurrent Compile() call causes "Garbage Collector" suspend all threads too often | ||
} | ||
#endif | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.