@@ -11,6 +11,8 @@ namespace Xtensive.Orm.Linq.Expressions.Visitors
1111{
1212 internal sealed class EnumRewriter : ExpressionVisitor
1313 {
14+ private readonly static System . Collections . Concurrent . ConcurrentDictionary < Type , Delegate > NullableValueCreators = new ( ) ;
15+
1416 public static Expression Rewrite ( Expression target )
1517 {
1618 return new EnumRewriter ( ) . Visit ( target ) ;
@@ -41,15 +43,36 @@ private Expression ConvertEnumConstant(ConstantExpression c)
4143 {
4244 if ( c . Type . StripNullable ( ) . IsEnum ) {
4345 var underlyingType = Enum . GetUnderlyingType ( c . Type . StripNullable ( ) ) ;
44- if ( c . Type . IsNullable ( ) )
45- underlyingType = WellKnownTypes . NullableOfT . CachedMakeGenericType ( underlyingType ) ;
46- var underlyingTypeValue = Convert . ChangeType ( c . Value , underlyingType ) ;
46+
47+ object underlyingTypeValue ;
48+ if ( c . Type . IsNullable ( ) ) {
49+ underlyingTypeValue = ( c . Value is null )
50+ ? null
51+ : CreateNullableUnderlyingValue ( c . Value , underlyingType ) ;
52+ }
53+ else {
54+ underlyingTypeValue = Convert . ChangeType ( c . Value , underlyingType ) ;
55+ }
4756 var constantExpression = Expression . Constant ( underlyingTypeValue ) ;
4857 return Expression . Convert ( constantExpression , c . Type ) ;
4958 }
5059 return c ;
5160 }
5261
62+ private static object CreateNullableUnderlyingValue ( object value , Type underlyingType )
63+ {
64+ var instanceCreator = NullableValueCreators . GetOrAdd ( underlyingType , ( t ) => {
65+ var parameter = Expression . Parameter ( underlyingType ) ;
66+ var type = WellKnownTypes . NullableOfT . MakeGenericType ( underlyingType ) ;
67+ var ctor = type . GetConstructors ( ) [ 0 ] ;
68+ var body = Expression . New ( ctor , parameter ) ;
69+ var instanceCreatorLambda = Expression . Lambda ( body , parameter ) ;
70+ return instanceCreatorLambda . Compile ( ) ;
71+ } ) ;
72+
73+ return instanceCreator . DynamicInvoke ( value ) ;
74+ }
75+
5376 private EnumRewriter ( )
5477 {
5578 }
0 commit comments