Skip to content

Commit ffce0e3

Browse files
committed
Add support for DefaultExpressions in expression visitors
1 parent ddfb977 commit ffce0e3

File tree

9 files changed

+155
-43
lines changed

9 files changed

+155
-43
lines changed

Extensions/Xtensive.Orm.BulkOperations/Internals/ExpressionVisitor.cs

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
// Copyright (C) 2019-2020 Xtensive LLC.
1+
// Copyright (C) 2019-2023 Xtensive LLC.
22
// This code is distributed under MIT license terms.
33
// See the License.txt file in the project root for more information.
44

55
using System;
66
using System.Collections.Generic;
77
using System.Collections.ObjectModel;
88
using System.Linq.Expressions;
9+
using Xtensive.Core;
910
using Xtensive.Linq;
1011

1112
namespace Xtensive.Orm.BulkOperations
@@ -95,6 +96,8 @@ protected virtual Expression Visit(Expression exp)
9596
return VisitConditional((ConditionalExpression) exp);
9697
case ExpressionType.Constant:
9798
return VisitConstant((ConstantExpression) exp);
99+
case ExpressionType.Default:
100+
return VisitDefault((DefaultExpression) exp);
98101
case ExpressionType.Parameter:
99102
return VisitParameter((ParameterExpression) exp);
100103
case ExpressionType.MemberAccess:
@@ -180,6 +183,11 @@ private Expression VisitConstant(ConstantExpression c)
180183
return c;
181184
}
182185

186+
private Expression VisitDefault(DefaultExpression d)
187+
{
188+
return d.ToConstantExpression();
189+
}
190+
183191
private ElementInit VisitElementInitializer(ElementInit initializer)
184192
{
185193
IEnumerable<Expression> arguments = VisitExpressionList(initializer.Arguments);

Orm/Xtensive.Orm/Core/Extensions/ExpressionExtensions.cs

+35-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (C) 2009-2020 Xtensive LLC.
1+
// Copyright (C) 2009-2023 Xtensive LLC.
22
// This code is distributed under MIT license terms.
33
// See the License.txt file in the project root for more information.
44
// Created by: Alexis Kochetov
@@ -12,6 +12,8 @@
1212
using Xtensive.Linq.SerializableExpressions.Internals;
1313

1414
using System.Linq;
15+
using Xtensive.Reflection;
16+
using System.Collections.Concurrent;
1517

1618
namespace Xtensive.Core
1719
{
@@ -20,6 +22,8 @@ namespace Xtensive.Core
2022
/// </summary>
2123
public static class ExpressionExtensions
2224
{
25+
private readonly static ConcurrentDictionary<Type, object> StructDefaultValues = new();
26+
2327
/// <summary>
2428
/// Formats the <paramref name="expression"/>.
2529
/// </summary>
@@ -105,12 +109,41 @@ public static SerializableExpression ToSerializableExpression(this Expression ex
105109
/// Converts specified <see cref="SerializableExpression"/> to <see cref="Expression"/>.
106110
/// </summary>
107111
/// <param name="expression">The expression to convert.</param>
108-
/// <returns></returns>
112+
/// <returns>Expression that represents given <see cref="SerializableExpression"/>.</returns>
109113
public static Expression ToExpression(this SerializableExpression expression)
110114
{
111115
return new SerializableExpressionToExpressionConverter(expression).Convert();
112116
}
113117

118+
/// <summary>
119+
/// Converts <see cref="DefaultExpression"/> to <see cref="ConstantExpression"/>
120+
/// with value of default value of type in the <paramref name="defaultExpression"/>.
121+
/// </summary>
122+
/// <param name="defaultExpression">The expression to convert.</param>
123+
/// <returns>Result constant expression.</returns>
124+
public static ConstantExpression ToConstantExpression(this DefaultExpression defaultExpression)
125+
{
126+
var value = GetDefaultValue(defaultExpression);
127+
128+
return Expression.Constant(value, defaultExpression.Type);
129+
}
130+
131+
/// <summary>
132+
/// Gets the value represented by given <see cref="DefaultExpression"/>.
133+
/// </summary>
134+
/// <param name="defaultExpression">The default value expression.</param>
135+
/// <returns>Object value of default value.</returns>
136+
public static object GetDefaultValue(this DefaultExpression defaultExpression)
137+
{
138+
if (defaultExpression.Type.IsValueType) {
139+
return StructDefaultValues.GetOrAdd<DefaultExpression>(
140+
defaultExpression.Type,
141+
(type, expr) => { return ((Func<object>) Expression.Lambda(Expression.Convert(expr, WellKnownTypes.Object)).Compile()).Invoke(); },
142+
defaultExpression);
143+
}
144+
return null;
145+
}
146+
114147
/// <summary>
115148
/// Gets return type of <see cref="LambdaExpression"/>.
116149
/// This method is used to write code that is compilable on .NET 3.5,

Orm/Xtensive.Orm/Linq/ExpressionVisitor.cs

+10-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1-
// Copyright (C) 2003-2010 Xtensive LLC.
2-
// All rights reserved.
3-
// For conditions of distribution and use, see license.
1+
// Copyright (C) 2008-2023 Xtensive LLC.
2+
// This code is distributed under MIT license terms.
3+
// See the License.txt file in the project root for more information.
44
// Created by: Alexey Kochetov
55
// Created: 2008.11.11
66

77
using System;
88
using System.Collections.Generic;
99
using System.Collections.ObjectModel;
1010
using System.Linq.Expressions;
11+
using Xtensive.Core;
1112

1213
namespace Xtensive.Linq
1314
{
@@ -96,6 +97,12 @@ protected override Expression VisitConstant(ConstantExpression c)
9697
return c;
9798
}
9899

100+
/// <inheritdoc/>
101+
protected override Expression VisitDefault(DefaultExpression d)
102+
{
103+
return d.ToConstantExpression();
104+
}
105+
99106
/// <inheritdoc/>
100107
protected override Expression VisitConditional(ConditionalExpression c)
101108
{

Orm/Xtensive.Orm/Linq/ExpressionVisitor{TResult}.cs

+10
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,9 @@ protected virtual TResult Visit(Expression e)
9696
case ExpressionType.Constant:
9797
result = VisitConstant((ConstantExpression) e);
9898
break;
99+
case ExpressionType.Default:
100+
result = VisitDefault((DefaultExpression) e);
101+
break;
99102
case ExpressionType.Parameter:
100103
result = VisitParameter((ParameterExpression) e);
101104
break;
@@ -189,6 +192,13 @@ protected virtual TResult VisitUnknown(Expression e)
189192
/// <param name="c">The constant expression.</param>
190193
/// <returns>Visit result.</returns>
191194
protected abstract TResult VisitConstant(ConstantExpression c);
195+
196+
/// <summary>
197+
/// Visits the default expression.
198+
/// </summary>
199+
/// <param name="d">The default expression.</param>
200+
/// <returns>Visit result.</returns>
201+
protected abstract TResult VisitDefault(DefaultExpression d);
192202

193203
/// <summary>
194204
/// Visits the conditional expression.

Orm/Xtensive.Orm/Linq/ExpressionWriter.cs

+23-15
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (C) 2008-2021 Xtensive LLC.
1+
// Copyright (C) 2008-2023 Xtensive LLC.
22
// This code is distributed under MIT license terms.
33
// See the License.txt file in the project root for more information.
44
// Created by: Alexey Kochetov
@@ -213,7 +213,7 @@ protected virtual string GetOperator(ExpressionType type)
213213
}
214214

215215
/// <inheritdoc/>
216-
protected override Expression VisitBinary(BinaryExpression b)
216+
protected override BinaryExpression VisitBinary(BinaryExpression b)
217217
{
218218
switch (b.NodeType) {
219219
case ExpressionType.ArrayIndex:
@@ -244,7 +244,7 @@ protected override Expression VisitBinary(BinaryExpression b)
244244
}
245245

246246
/// <inheritdoc/>
247-
protected override Expression VisitUnary(UnaryExpression u)
247+
protected override UnaryExpression VisitUnary(UnaryExpression u)
248248
{
249249
switch (u.NodeType) {
250250
case ExpressionType.Convert:
@@ -307,7 +307,7 @@ protected virtual string GetTypeName(Type type)
307307
}
308308

309309
/// <inheritdoc/>
310-
protected override Expression VisitConditional(ConditionalExpression c)
310+
protected override ConditionalExpression VisitConditional(ConditionalExpression c)
311311
{
312312
Visit(c.Test);
313313
WriteLine(IndentType.Inner);
@@ -335,7 +335,7 @@ protected override System.Collections.ObjectModel.ReadOnlyCollection<MemberBindi
335335
}
336336

337337
/// <inheritdoc/>
338-
protected override Expression VisitConstant(ConstantExpression c)
338+
protected override ConstantExpression VisitConstant(ConstantExpression c)
339339
{
340340
var type = c.Type;
341341
if (type.Name.IndexOf("__DisplayClass", StringComparison.Ordinal) > 0 &&
@@ -400,6 +400,14 @@ protected override Expression VisitConstant(ConstantExpression c)
400400
return c;
401401
}
402402

403+
protected override DefaultExpression VisitDefault(DefaultExpression d)
404+
{
405+
Write("default(");
406+
Write(GetTypeName(d.Type));
407+
Write(")");
408+
return d;
409+
}
410+
403411
/// <inheritdoc/>
404412
protected override ElementInit VisitElementInitializer(ElementInit initializer)
405413
{
@@ -452,7 +460,7 @@ protected override System.Collections.ObjectModel.ReadOnlyCollection<Expression>
452460
}
453461

454462
/// <inheritdoc/>
455-
protected override Expression VisitInvocation(InvocationExpression i)
463+
protected override InvocationExpression VisitInvocation(InvocationExpression i)
456464
{
457465
Write("Invoke(");
458466
WriteLine(IndentType.Inner);
@@ -467,7 +475,7 @@ protected override Expression VisitInvocation(InvocationExpression i)
467475
}
468476

469477
/// <inheritdoc/>
470-
protected override Expression VisitLambda(LambdaExpression l)
478+
protected override LambdaExpression VisitLambda(LambdaExpression l)
471479
{
472480
if (l.Parameters.Count > 1) {
473481
Write("(");
@@ -493,7 +501,7 @@ protected override Expression VisitLambda(LambdaExpression l)
493501
}
494502

495503
/// <inheritdoc/>
496-
protected override Expression VisitListInit(ListInitExpression li)
504+
protected override ListInitExpression VisitListInit(ListInitExpression li)
497505
{
498506
Visit(li.NewExpression);
499507
Write(" {");
@@ -505,7 +513,7 @@ protected override Expression VisitListInit(ListInitExpression li)
505513
}
506514

507515
/// <inheritdoc/>
508-
protected override Expression VisitMemberAccess(MemberExpression m)
516+
protected override MemberExpression VisitMemberAccess(MemberExpression m)
509517
{
510518
Visit(m.Expression);
511519
Write(".");
@@ -523,7 +531,7 @@ protected override MemberAssignment VisitMemberAssignment(MemberAssignment ma)
523531
}
524532

525533
/// <inheritdoc/>
526-
protected override Expression VisitMemberInit(MemberInitExpression mi)
534+
protected override MemberInitExpression VisitMemberInit(MemberInitExpression mi)
527535
{
528536
Visit(mi.NewExpression);
529537
Write(" {");
@@ -559,7 +567,7 @@ protected override MemberMemberBinding VisitMemberMemberBinding(MemberMemberBind
559567
}
560568

561569
/// <inheritdoc/>
562-
protected override Expression VisitMethodCall(MethodCallExpression mc)
570+
protected override MethodCallExpression VisitMethodCall(MethodCallExpression mc)
563571
{
564572
var arguments = mc.Arguments;
565573
if (mc.Object != null) {
@@ -584,7 +592,7 @@ protected override Expression VisitMethodCall(MethodCallExpression mc)
584592
}
585593

586594
/// <inheritdoc/>
587-
protected override Expression VisitNew(NewExpression n)
595+
protected override NewExpression VisitNew(NewExpression n)
588596
{
589597
Write("new ");
590598
Write(GetTypeName(n.Type));
@@ -593,7 +601,7 @@ protected override Expression VisitNew(NewExpression n)
593601
}
594602

595603
/// <inheritdoc/>
596-
protected override Expression VisitNewArray(NewArrayExpression na)
604+
protected override NewArrayExpression VisitNewArray(NewArrayExpression na)
597605
{
598606
Write("new ");
599607
Write(GetTypeName(SequenceHelper.GetElementType(na.Type)));
@@ -602,14 +610,14 @@ protected override Expression VisitNewArray(NewArrayExpression na)
602610
}
603611

604612
/// <inheritdoc/>
605-
protected override Expression VisitParameter(ParameterExpression p)
613+
protected override ParameterExpression VisitParameter(ParameterExpression p)
606614
{
607615
Write(p.Name);
608616
return p;
609617
}
610618

611619
/// <inheritdoc/>
612-
protected override Expression VisitTypeIs(TypeBinaryExpression tb)
620+
protected override TypeBinaryExpression VisitTypeIs(TypeBinaryExpression tb)
613621
{
614622
Visit(tb.Expression);
615623
Write(" is ");

Orm/Xtensive.Orm/Linq/Internals/ExpressionHashCodeCalculator.cs

+14-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
// Copyright (C) 2003-2010 Xtensive LLC.
2-
// All rights reserved.
3-
// For conditions of distribution and use, see license.
1+
// Copyright (C) 2008-2023 Xtensive LLC.
2+
// This code is distributed under MIT license terms.
3+
// See the License.txt file in the project root for more information.
44
// Created by: Denis Krjuchkov
55
// Created: 2009.05.06
66

77
using System;
8+
using System.Collections.Concurrent;
89
using System.Collections.Generic;
910
using System.Linq;
1011
using System.Linq.Expressions;
@@ -60,6 +61,16 @@ protected override int VisitConstant(ConstantExpression c)
6061
return c.Value != null ? c.Value.GetHashCode() : NullHashCode;
6162
}
6263

64+
protected override int VisitDefault(DefaultExpression d)
65+
{
66+
if (d.Type.IsValueType) {
67+
return d.GetDefaultValue().GetHashCode();
68+
}
69+
else {
70+
return NullHashCode;
71+
}
72+
}
73+
6374
protected override int VisitConditional(ConditionalExpression c)
6475
{
6576
return Visit(c.Test) ^ Visit(c.IfTrue) ^ Visit(c.IfFalse);

0 commit comments

Comments
 (0)