Remove typed modify extension methods in favor of typed builders

This commit is contained in:
root
2026-02-26 18:48:01 +01:00
parent 23a0336b7e
commit 13936d8598
7 changed files with 215 additions and 332 deletions

View File

@@ -7526,135 +7526,6 @@ namespace DynamORM
return builder.Join(on, alias, DynamicJoinType.Full); return builder.Join(on, alias, DynamicJoinType.Full);
} }
} }
/// <summary>Typed helper extensions for update/insert/delete fluent APIs.</summary>
public static class TypedModifyExtensions
{
/// <summary>Add typed where predicate (AND-composed comparisons) for update builder.</summary>
public static IDynamicUpdateQueryBuilder WhereTyped<T>(this IDynamicUpdateQueryBuilder builder, Expression<Func<T, bool>> predicate)
{
AddTypedWhere(builder, predicate == null ? null : predicate.Body);
return builder;
}
/// <summary>Add typed where predicate (AND-composed comparisons) for delete builder.</summary>
public static IDynamicDeleteQueryBuilder WhereTyped<T>(this IDynamicDeleteQueryBuilder builder, Expression<Func<T, bool>> predicate)
{
AddTypedWhere(builder, predicate == null ? null : predicate.Body);
return builder;
}
/// <summary>Add typed value assignment for update builder.</summary>
public static IDynamicUpdateQueryBuilder SetTyped<T, TValue>(this IDynamicUpdateQueryBuilder builder, Expression<Func<T, TValue>> selector, object value)
{
string col = GetColumnName(typeof(T), selector == null ? null : selector.Body);
return builder.Values(col, value);
}
/// <summary>Add typed value assignment for insert builder.</summary>
public static IDynamicInsertQueryBuilder InsertTyped<T, TValue>(this IDynamicInsertQueryBuilder builder, Expression<Func<T, TValue>> selector, object value)
{
string col = GetColumnName(typeof(T), selector == null ? null : selector.Body);
return builder.Insert(col, value);
}
/// <summary>Insert mapped object with compile-time type information.</summary>
public static IDynamicInsertQueryBuilder InsertTyped<T>(this IDynamicInsertQueryBuilder builder, T value) where T : class
{
return builder.Insert(value);
}
/// <summary>Update mapped object with compile-time type information.</summary>
public static IDynamicUpdateQueryBuilder UpdateTyped<T>(this IDynamicUpdateQueryBuilder builder, T value) where T : class
{
return builder.Update(value);
}
private static void AddTypedWhere(dynamic builder, Expression expression)
{
if (expression == null)
throw new ArgumentNullException("predicate");
expression = UnwrapConvert(expression);
BinaryExpression be = expression as BinaryExpression;
if (be != null && (be.NodeType == ExpressionType.AndAlso || be.NodeType == ExpressionType.And))
{
AddTypedWhere(builder, be.Left);
AddTypedWhere(builder, be.Right);
return;
}
if (be != null)
{
string col = GetColumnName(GetRootParameterType(be.Left), be.Left);
object val = EvaluateExpression(be.Right);
switch (be.NodeType)
{
case ExpressionType.Equal:
builder.Where(col, DynamicColumn.CompareOperator.Eq, val);
return;
case ExpressionType.NotEqual:
builder.Where(col, DynamicColumn.CompareOperator.Not, val);
return;
case ExpressionType.GreaterThan:
builder.Where(col, DynamicColumn.CompareOperator.Gt, val);
return;
case ExpressionType.GreaterThanOrEqual:
builder.Where(col, DynamicColumn.CompareOperator.Gte, val);
return;
case ExpressionType.LessThan:
builder.Where(col, DynamicColumn.CompareOperator.Lt, val);
return;
case ExpressionType.LessThanOrEqual:
builder.Where(col, DynamicColumn.CompareOperator.Lte, val);
return;
}
}
throw new NotSupportedException(string.Format("Typed where expression is currently limited to AND-composed binary comparisons: {0}", expression));
}
private static Type GetRootParameterType(Expression expression)
{
expression = UnwrapConvert(expression);
MemberExpression m = expression as MemberExpression;
if (m != null && m.Expression is ParameterExpression)
return ((ParameterExpression)m.Expression).Type;
throw new NotSupportedException(string.Format("Unsupported typed selector: {0}", expression));
}
private static string GetColumnName(Type modelType, Expression expression)
{
if (modelType == null)
modelType = GetRootParameterType(expression);
expression = UnwrapConvert(expression);
MemberExpression member = expression as MemberExpression;
if (member == null)
throw new NotSupportedException(string.Format("Selector must target a mapped property: {0}", expression));
DynamicTypeMap mapper = DynamicMapperCache.GetMapper(modelType);
if (mapper == null)
throw new InvalidOperationException(string.Format("Cant assign unmapable type as a table ({0}).", modelType.FullName));
string col = mapper.PropertyMap.TryGetValue(member.Member.Name)
?? mapper.PropertyMap
.Where(x => string.Equals(x.Key, member.Member.Name, StringComparison.OrdinalIgnoreCase))
.Select(x => x.Value)
.FirstOrDefault()
?? member.Member.Name;
return col;
}
private static Expression UnwrapConvert(Expression expression)
{
while (expression is UnaryExpression &&
(((UnaryExpression)expression).NodeType == ExpressionType.Convert ||
((UnaryExpression)expression).NodeType == ExpressionType.ConvertChecked))
expression = ((UnaryExpression)expression).Operand;
return expression;
}
private static object EvaluateExpression(Expression expression)
{
expression = UnwrapConvert(expression);
var objectMember = Expression.Convert(expression, typeof(object));
var getter = Expression.Lambda<Func<object>>(objectMember).Compile();
return getter();
}
}
namespace Extensions namespace Extensions
{ {
internal static class DynamicHavingQueryExtensions internal static class DynamicHavingQueryExtensions
@@ -10679,7 +10550,7 @@ namespace DynamORM
} }
public IDynamicTypedDeleteQueryBuilder<T> Where(Expression<Func<T, bool>> predicate) public IDynamicTypedDeleteQueryBuilder<T> Where(Expression<Func<T, bool>> predicate)
{ {
this.WhereTyped(predicate); TypedModifyHelper.ApplyWhere<T>((c, o, v) => base.Where(c, o, v), predicate);
return this; return this;
} }
public new IDynamicTypedDeleteQueryBuilder<T> Where(Func<dynamic, object> func) public new IDynamicTypedDeleteQueryBuilder<T> Where(Func<dynamic, object> func)
@@ -10718,7 +10589,7 @@ namespace DynamORM
} }
public IDynamicTypedInsertQueryBuilder<T> Insert<TValue>(Expression<Func<T, TValue>> selector, object value) public IDynamicTypedInsertQueryBuilder<T> Insert<TValue>(Expression<Func<T, TValue>> selector, object value)
{ {
this.InsertTyped(selector, value); base.Insert(TypedModifyHelper.GetMappedColumn(selector), value);
return this; return this;
} }
public IDynamicTypedInsertQueryBuilder<T> Insert(T value) public IDynamicTypedInsertQueryBuilder<T> Insert(T value)
@@ -11290,12 +11161,12 @@ namespace DynamORM
} }
public IDynamicTypedUpdateQueryBuilder<T> Where(Expression<Func<T, bool>> predicate) public IDynamicTypedUpdateQueryBuilder<T> Where(Expression<Func<T, bool>> predicate)
{ {
this.WhereTyped(predicate); TypedModifyHelper.ApplyWhere<T>((c, o, v) => base.Where(c, o, v), predicate);
return this; return this;
} }
public IDynamicTypedUpdateQueryBuilder<T> Set<TValue>(Expression<Func<T, TValue>> selector, object value) public IDynamicTypedUpdateQueryBuilder<T> Set<TValue>(Expression<Func<T, TValue>> selector, object value)
{ {
this.SetTyped(selector, value); base.Values(TypedModifyHelper.GetMappedColumn(selector), value);
return this; return this;
} }
public IDynamicTypedUpdateQueryBuilder<T> Values(T value) public IDynamicTypedUpdateQueryBuilder<T> Values(T value)
@@ -11634,6 +11505,99 @@ namespace DynamORM
} }
#endregion IExtendedDisposable #endregion IExtendedDisposable
} }
/// <summary>Helper methods for typed modify builders.</summary>
internal static class TypedModifyHelper
{
public static string GetMappedColumn<T, TValue>(Expression<Func<T, TValue>> selector)
{
if (selector == null)
throw new ArgumentNullException("selector");
return GetMappedColumn(typeof(T), selector.Body);
}
public static void ApplyWhere<T>(Action<string, DynamicColumn.CompareOperator, object> addCondition, Expression<Func<T, bool>> predicate)
{
if (addCondition == null)
throw new ArgumentNullException("addCondition");
if (predicate == null)
throw new ArgumentNullException("predicate");
ApplyWhereInternal(typeof(T), addCondition, predicate.Body);
}
private static void ApplyWhereInternal(Type modelType, Action<string, DynamicColumn.CompareOperator, object> addCondition, Expression expression)
{
expression = UnwrapConvert(expression);
BinaryExpression be = expression as BinaryExpression;
if (be == null)
throw new NotSupportedException(string.Format("Typed where expression is currently limited to AND-composed binary comparisons: {0}", expression));
if (be.NodeType == ExpressionType.AndAlso || be.NodeType == ExpressionType.And)
{
ApplyWhereInternal(modelType, addCondition, be.Left);
ApplyWhereInternal(modelType, addCondition, be.Right);
return;
}
string col = GetMappedColumn(modelType, be.Left);
object val = EvaluateExpression(be.Right);
switch (be.NodeType)
{
case ExpressionType.Equal:
addCondition(col, DynamicColumn.CompareOperator.Eq, val);
return;
case ExpressionType.NotEqual:
addCondition(col, DynamicColumn.CompareOperator.Not, val);
return;
case ExpressionType.GreaterThan:
addCondition(col, DynamicColumn.CompareOperator.Gt, val);
return;
case ExpressionType.GreaterThanOrEqual:
addCondition(col, DynamicColumn.CompareOperator.Gte, val);
return;
case ExpressionType.LessThan:
addCondition(col, DynamicColumn.CompareOperator.Lt, val);
return;
case ExpressionType.LessThanOrEqual:
addCondition(col, DynamicColumn.CompareOperator.Lte, val);
return;
}
throw new NotSupportedException(string.Format("Typed where expression is currently limited to AND-composed binary comparisons: {0}", expression));
}
private static string GetMappedColumn(Type modelType, Expression expression)
{
expression = UnwrapConvert(expression);
MemberExpression member = expression as MemberExpression;
if (member == null)
throw new NotSupportedException(string.Format("Selector must target a mapped property: {0}", expression));
DynamicTypeMap mapper = DynamicMapperCache.GetMapper(modelType);
if (mapper == null)
throw new InvalidOperationException(string.Format("Cant assign unmapable type as a table ({0}).", modelType.FullName));
return mapper.PropertyMap.TryGetValue(member.Member.Name)
?? mapper.PropertyMap
.Where(x => string.Equals(x.Key, member.Member.Name, StringComparison.OrdinalIgnoreCase))
.Select(x => x.Value)
.FirstOrDefault()
?? member.Member.Name;
}
private static Expression UnwrapConvert(Expression expression)
{
while (expression is UnaryExpression &&
(((UnaryExpression)expression).NodeType == ExpressionType.Convert ||
((UnaryExpression)expression).NodeType == ExpressionType.ConvertChecked))
expression = ((UnaryExpression)expression).Operand;
return expression;
}
private static object EvaluateExpression(Expression expression)
{
expression = UnwrapConvert(expression);
var objectMember = Expression.Convert(expression, typeof(object));
var getter = Expression.Lambda<Func<object>>(objectMember).Compile();
return getter();
}
}
} }
} }
namespace Helpers namespace Helpers

View File

@@ -32,21 +32,6 @@ namespace DynamORM.Tests.Modify
DestroyTestDatabase(); DestroyTestDatabase();
} }
[Test]
public void TestTypedUpdateSetAndWhere()
{
var cmd = Database.Update<Users>()
.SetTyped<Users, string>(u => u.Code, "777")
.WhereTyped<Users>(u => u.Id == 1 && u.Code == "1");
Assert.AreEqual(
string.Format("UPDATE \"sample_users\" SET \"code\" = [${0}] WHERE (\"id\" = [${1}]) AND (\"code\" = [${2}])",
cmd.Parameters.Keys.ElementAt(0),
cmd.Parameters.Keys.ElementAt(1),
cmd.Parameters.Keys.ElementAt(2)),
cmd.CommandText());
}
[Test] [Test]
public void TestTypedUpdateBuilderSetAndWhere() public void TestTypedUpdateBuilderSetAndWhere()
{ {
@@ -62,17 +47,6 @@ namespace DynamORM.Tests.Modify
cmd.CommandText()); cmd.CommandText());
} }
[Test]
public void TestTypedDeleteWhere()
{
var cmd = Database.Delete<Users>()
.WhereTyped<Users>(u => u.Id == 2);
Assert.AreEqual(
string.Format("DELETE FROM \"sample_users\" WHERE (\"id\" = [${0}])", cmd.Parameters.Keys.First()),
cmd.CommandText());
}
[Test] [Test]
public void TestTypedDeleteBuilderWhere() public void TestTypedDeleteBuilderWhere()
{ {
@@ -84,20 +58,6 @@ namespace DynamORM.Tests.Modify
cmd.CommandText()); cmd.CommandText());
} }
[Test]
public void TestTypedInsertColumns()
{
var cmd = Database.Insert<Users>()
.InsertTyped<Users, string>(u => u.Code, "900")
.InsertTyped<Users, string>(u => u.First, "Typed");
Assert.AreEqual(
string.Format("INSERT INTO \"sample_users\" (\"code\", \"first\") VALUES ([${0}], [${1}])",
cmd.Parameters.Keys.ElementAt(0),
cmd.Parameters.Keys.ElementAt(1)),
cmd.CommandText());
}
[Test] [Test]
public void TestTypedInsertBuilderColumns() public void TestTypedInsertBuilderColumns()
{ {

View File

@@ -20,7 +20,7 @@ namespace DynamORM.Builders.Implementation
public IDynamicTypedDeleteQueryBuilder<T> Where(Expression<Func<T, bool>> predicate) public IDynamicTypedDeleteQueryBuilder<T> Where(Expression<Func<T, bool>> predicate)
{ {
this.WhereTyped(predicate); TypedModifyHelper.ApplyWhere<T>((c, o, v) => base.Where(c, o, v), predicate);
return this; return this;
} }

View File

@@ -20,7 +20,7 @@ namespace DynamORM.Builders.Implementation
public IDynamicTypedInsertQueryBuilder<T> Insert<TValue>(Expression<Func<T, TValue>> selector, object value) public IDynamicTypedInsertQueryBuilder<T> Insert<TValue>(Expression<Func<T, TValue>> selector, object value)
{ {
this.InsertTyped(selector, value); base.Insert(TypedModifyHelper.GetMappedColumn(selector), value);
return this; return this;
} }

View File

@@ -20,13 +20,13 @@ namespace DynamORM.Builders.Implementation
public IDynamicTypedUpdateQueryBuilder<T> Where(Expression<Func<T, bool>> predicate) public IDynamicTypedUpdateQueryBuilder<T> Where(Expression<Func<T, bool>> predicate)
{ {
this.WhereTyped(predicate); TypedModifyHelper.ApplyWhere<T>((c, o, v) => base.Where(c, o, v), predicate);
return this; return this;
} }
public IDynamicTypedUpdateQueryBuilder<T> Set<TValue>(Expression<Func<T, TValue>> selector, object value) public IDynamicTypedUpdateQueryBuilder<T> Set<TValue>(Expression<Func<T, TValue>> selector, object value)
{ {
this.SetTyped(selector, value); base.Values(TypedModifyHelper.GetMappedColumn(selector), value);
return this; return this;
} }

View File

@@ -0,0 +1,114 @@
/*
* DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved.
*/
using System;
using System.Linq;
using System.Linq.Expressions;
using DynamORM.Mapper;
namespace DynamORM.Builders.Implementation
{
/// <summary>Helper methods for typed modify builders.</summary>
internal static class TypedModifyHelper
{
public static string GetMappedColumn<T, TValue>(Expression<Func<T, TValue>> selector)
{
if (selector == null)
throw new ArgumentNullException("selector");
return GetMappedColumn(typeof(T), selector.Body);
}
public static void ApplyWhere<T>(Action<string, DynamicColumn.CompareOperator, object> addCondition, Expression<Func<T, bool>> predicate)
{
if (addCondition == null)
throw new ArgumentNullException("addCondition");
if (predicate == null)
throw new ArgumentNullException("predicate");
ApplyWhereInternal(typeof(T), addCondition, predicate.Body);
}
private static void ApplyWhereInternal(Type modelType, Action<string, DynamicColumn.CompareOperator, object> addCondition, Expression expression)
{
expression = UnwrapConvert(expression);
BinaryExpression be = expression as BinaryExpression;
if (be == null)
throw new NotSupportedException(string.Format("Typed where expression is currently limited to AND-composed binary comparisons: {0}", expression));
if (be.NodeType == ExpressionType.AndAlso || be.NodeType == ExpressionType.And)
{
ApplyWhereInternal(modelType, addCondition, be.Left);
ApplyWhereInternal(modelType, addCondition, be.Right);
return;
}
string col = GetMappedColumn(modelType, be.Left);
object val = EvaluateExpression(be.Right);
switch (be.NodeType)
{
case ExpressionType.Equal:
addCondition(col, DynamicColumn.CompareOperator.Eq, val);
return;
case ExpressionType.NotEqual:
addCondition(col, DynamicColumn.CompareOperator.Not, val);
return;
case ExpressionType.GreaterThan:
addCondition(col, DynamicColumn.CompareOperator.Gt, val);
return;
case ExpressionType.GreaterThanOrEqual:
addCondition(col, DynamicColumn.CompareOperator.Gte, val);
return;
case ExpressionType.LessThan:
addCondition(col, DynamicColumn.CompareOperator.Lt, val);
return;
case ExpressionType.LessThanOrEqual:
addCondition(col, DynamicColumn.CompareOperator.Lte, val);
return;
}
throw new NotSupportedException(string.Format("Typed where expression is currently limited to AND-composed binary comparisons: {0}", expression));
}
private static string GetMappedColumn(Type modelType, Expression expression)
{
expression = UnwrapConvert(expression);
MemberExpression member = expression as MemberExpression;
if (member == null)
throw new NotSupportedException(string.Format("Selector must target a mapped property: {0}", expression));
DynamicTypeMap mapper = DynamicMapperCache.GetMapper(modelType);
if (mapper == null)
throw new InvalidOperationException(string.Format("Cant assign unmapable type as a table ({0}).", modelType.FullName));
return mapper.PropertyMap.TryGetValue(member.Member.Name)
?? mapper.PropertyMap
.Where(x => string.Equals(x.Key, member.Member.Name, StringComparison.OrdinalIgnoreCase))
.Select(x => x.Value)
.FirstOrDefault()
?? member.Member.Name;
}
private static Expression UnwrapConvert(Expression expression)
{
while (expression is UnaryExpression &&
(((UnaryExpression)expression).NodeType == ExpressionType.Convert ||
((UnaryExpression)expression).NodeType == ExpressionType.ConvertChecked))
expression = ((UnaryExpression)expression).Operand;
return expression;
}
private static object EvaluateExpression(Expression expression)
{
expression = UnwrapConvert(expression);
var objectMember = Expression.Convert(expression, typeof(object));
var getter = Expression.Lambda<Func<object>>(objectMember).Compile();
return getter();
}
}
}

View File

@@ -1,155 +0,0 @@
/*
* DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved.
*/
using System;
using System.Linq;
using System.Linq.Expressions;
using DynamORM.Mapper;
namespace DynamORM.Builders
{
/// <summary>Typed helper extensions for update/insert/delete fluent APIs.</summary>
public static class TypedModifyExtensions
{
/// <summary>Add typed where predicate (AND-composed comparisons) for update builder.</summary>
public static IDynamicUpdateQueryBuilder WhereTyped<T>(this IDynamicUpdateQueryBuilder builder, Expression<Func<T, bool>> predicate)
{
AddTypedWhere(builder, predicate == null ? null : predicate.Body);
return builder;
}
/// <summary>Add typed where predicate (AND-composed comparisons) for delete builder.</summary>
public static IDynamicDeleteQueryBuilder WhereTyped<T>(this IDynamicDeleteQueryBuilder builder, Expression<Func<T, bool>> predicate)
{
AddTypedWhere(builder, predicate == null ? null : predicate.Body);
return builder;
}
/// <summary>Add typed value assignment for update builder.</summary>
public static IDynamicUpdateQueryBuilder SetTyped<T, TValue>(this IDynamicUpdateQueryBuilder builder, Expression<Func<T, TValue>> selector, object value)
{
string col = GetColumnName(typeof(T), selector == null ? null : selector.Body);
return builder.Values(col, value);
}
/// <summary>Add typed value assignment for insert builder.</summary>
public static IDynamicInsertQueryBuilder InsertTyped<T, TValue>(this IDynamicInsertQueryBuilder builder, Expression<Func<T, TValue>> selector, object value)
{
string col = GetColumnName(typeof(T), selector == null ? null : selector.Body);
return builder.Insert(col, value);
}
/// <summary>Insert mapped object with compile-time type information.</summary>
public static IDynamicInsertQueryBuilder InsertTyped<T>(this IDynamicInsertQueryBuilder builder, T value) where T : class
{
return builder.Insert(value);
}
/// <summary>Update mapped object with compile-time type information.</summary>
public static IDynamicUpdateQueryBuilder UpdateTyped<T>(this IDynamicUpdateQueryBuilder builder, T value) where T : class
{
return builder.Update(value);
}
private static void AddTypedWhere(dynamic builder, Expression expression)
{
if (expression == null)
throw new ArgumentNullException("predicate");
expression = UnwrapConvert(expression);
BinaryExpression be = expression as BinaryExpression;
if (be != null && (be.NodeType == ExpressionType.AndAlso || be.NodeType == ExpressionType.And))
{
AddTypedWhere(builder, be.Left);
AddTypedWhere(builder, be.Right);
return;
}
if (be != null)
{
string col = GetColumnName(GetRootParameterType(be.Left), be.Left);
object val = EvaluateExpression(be.Right);
switch (be.NodeType)
{
case ExpressionType.Equal:
builder.Where(col, DynamicColumn.CompareOperator.Eq, val);
return;
case ExpressionType.NotEqual:
builder.Where(col, DynamicColumn.CompareOperator.Not, val);
return;
case ExpressionType.GreaterThan:
builder.Where(col, DynamicColumn.CompareOperator.Gt, val);
return;
case ExpressionType.GreaterThanOrEqual:
builder.Where(col, DynamicColumn.CompareOperator.Gte, val);
return;
case ExpressionType.LessThan:
builder.Where(col, DynamicColumn.CompareOperator.Lt, val);
return;
case ExpressionType.LessThanOrEqual:
builder.Where(col, DynamicColumn.CompareOperator.Lte, val);
return;
}
}
throw new NotSupportedException(string.Format("Typed where expression is currently limited to AND-composed binary comparisons: {0}", expression));
}
private static Type GetRootParameterType(Expression expression)
{
expression = UnwrapConvert(expression);
MemberExpression m = expression as MemberExpression;
if (m != null && m.Expression is ParameterExpression)
return ((ParameterExpression)m.Expression).Type;
throw new NotSupportedException(string.Format("Unsupported typed selector: {0}", expression));
}
private static string GetColumnName(Type modelType, Expression expression)
{
if (modelType == null)
modelType = GetRootParameterType(expression);
expression = UnwrapConvert(expression);
MemberExpression member = expression as MemberExpression;
if (member == null)
throw new NotSupportedException(string.Format("Selector must target a mapped property: {0}", expression));
DynamicTypeMap mapper = DynamicMapperCache.GetMapper(modelType);
if (mapper == null)
throw new InvalidOperationException(string.Format("Cant assign unmapable type as a table ({0}).", modelType.FullName));
string col = mapper.PropertyMap.TryGetValue(member.Member.Name)
?? mapper.PropertyMap
.Where(x => string.Equals(x.Key, member.Member.Name, StringComparison.OrdinalIgnoreCase))
.Select(x => x.Value)
.FirstOrDefault()
?? member.Member.Name;
return col;
}
private static Expression UnwrapConvert(Expression expression)
{
while (expression is UnaryExpression &&
(((UnaryExpression)expression).NodeType == ExpressionType.Convert ||
((UnaryExpression)expression).NodeType == ExpressionType.ConvertChecked))
expression = ((UnaryExpression)expression).Operand;
return expression;
}
private static object EvaluateExpression(Expression expression)
{
expression = UnwrapConvert(expression);
var objectMember = Expression.Convert(expression, typeof(object));
var getter = Expression.Lambda<Func<object>>(objectMember).Compile();
return getter();
}
}
}