mirror of
https://github.com/DevExpress/netcore-winforms-demos.git
synced 2025-12-24 02:21:11 +00:00
146 lines
8.7 KiB
C#
146 lines
8.7 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Linq.Expressions;
|
|
using System.Reflection;
|
|
|
|
namespace DevExpress.DevAV.Common.Utils {
|
|
/// <summary>
|
|
/// Provides methods to perform operations with lambda expression trees.
|
|
/// </summary>
|
|
public class ExpressionHelper {
|
|
class ValueHolder<T> {
|
|
public readonly T value;
|
|
public ValueHolder(T value) {
|
|
this.value = value;
|
|
}
|
|
}
|
|
|
|
static readonly Dictionary<Type, object> TraitsCache = new Dictionary<Type, object>();
|
|
|
|
/// <summary>
|
|
/// Builds a lambda expression that compares an entity property value with a given constant value.
|
|
/// </summary>
|
|
/// <typeparam name="TPropertyOwner">An owner type of the property.</typeparam>
|
|
/// <typeparam name="TProperty">A primary key property type.</typeparam>
|
|
/// <param name="getPropertyExpression">A lambda expression that returns the property value for a given entity.</param>
|
|
/// <param name="constant">A constant value to compare with entity property value.</param>
|
|
public static Expression<Func<TPropertyOwner, bool>> GetValueEqualsExpression<TPropertyOwner, TProperty>(Expression<Func<TPropertyOwner, TProperty>> getPropertyExpression, TProperty constant) {
|
|
Expression equalExpression = Expression.Equal(getPropertyExpression.Body, Expression.Convert(Expression.Field(Expression.Constant(new ValueHolder<TProperty>(constant)), "value"), getPropertyExpression.Body.Type));
|
|
return Expression.Lambda<Func<TPropertyOwner, bool>>(equalExpression, getPropertyExpression.Parameters.Single());
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns an instance of the EntityTraits class that encapsulates operations to obtain and set the primary key value of a given entity.
|
|
/// </summary>
|
|
/// <typeparam name="TOwner">A type used as a key to cache compiled lambda expressions.</typeparam>
|
|
/// <typeparam name="TPropertyOwner">An owner type of the primary key property.</typeparam>
|
|
/// <typeparam name="TProperty">A primary key property type.</typeparam>
|
|
/// <param name="owner">An instance of the TOwner type which type is used as a key to cache compiled lambda expressions.</param>
|
|
/// <param name="getPropertyExpression">A lambda expression that returns the primary key value for a given entity.</param>
|
|
public static EntityTraits<TPropertyOwner, TProperty> GetEntityTraits<TOwner, TPropertyOwner, TProperty>(TOwner owner, Expression<Func<TPropertyOwner, TProperty>> getPropertyExpression) {
|
|
object traits = null;
|
|
if(!TraitsCache.TryGetValue(owner.GetType(), out traits)) {
|
|
traits = new EntityTraits<TPropertyOwner, TProperty>(getPropertyExpression.Compile(), GetSetValueActionExpression(getPropertyExpression).Compile(), GetHasValueFunctionExpression(getPropertyExpression).Compile());
|
|
TraitsCache[owner.GetType()] = traits;
|
|
}
|
|
return (EntityTraits<TPropertyOwner, TProperty>)traits;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines whether the given entity satisfies the condition represented by a lambda expression.
|
|
/// </summary>
|
|
/// <typeparam name="TEntity">A type of the given object.</typeparam>
|
|
/// <param name="entity">An object to test.</param>
|
|
/// <param name="predicate">A function that determines whether the given object satisfies the condition.</param>
|
|
public static bool IsFitEntity<TEntity>(TEntity entity, Expression<Func<TEntity, bool>> predicate) where TEntity : class {
|
|
return predicate == null || (new TEntity[] { entity }.AsQueryable().Any(predicate));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Converts a property reference represented as a lambda expression to a property name.
|
|
/// </summary>
|
|
/// <param name="expression">A lambda expression that returns the property value.</param>
|
|
public static string GetPropertyName(LambdaExpression expression) {
|
|
Expression body = expression.Body;
|
|
if(body is UnaryExpression) {
|
|
body = ((UnaryExpression)body).Operand;
|
|
}
|
|
var memberExpression = ValidateMemberExpression((MemberExpression)body);
|
|
return memberExpression.Member.Name;
|
|
}
|
|
|
|
static MemberExpression ValidateMemberExpression(MemberExpression memberExpression) {
|
|
if(IsNullableValueExpression(memberExpression))
|
|
memberExpression = (MemberExpression)memberExpression.Expression;
|
|
return memberExpression;
|
|
}
|
|
|
|
static bool IsNullableValueExpression(MemberExpression memberExpression) {
|
|
var propertyInfo = (PropertyInfo)memberExpression.Member;
|
|
return propertyInfo.PropertyType.IsValueType && propertyInfo.ReflectedType == typeof(Nullable<>).MakeGenericType(propertyInfo.PropertyType) && propertyInfo.Name == "Value";
|
|
}
|
|
|
|
static Expression<Action<TPropertyOwner, TProperty>> GetSetValueActionExpression<TPropertyOwner, TProperty>(Expression<Func<TPropertyOwner, TProperty>> getPropertyExpression) {
|
|
MemberExpression body = ValidateMemberExpression((MemberExpression)getPropertyExpression.Body);
|
|
ParameterExpression thisParameter = getPropertyExpression.Parameters.Single();
|
|
ParameterExpression propertyValueParameter = Expression.Parameter(typeof(TProperty), "propertyValue");
|
|
|
|
Expression keyValueExpression = propertyValueParameter;
|
|
if(IsNullableValueExpression((MemberExpression)getPropertyExpression.Body)) {
|
|
var constructor = typeof(Nullable<>).MakeGenericType(typeof(TProperty)).GetConstructor(new Type[] { typeof(TProperty) });
|
|
keyValueExpression = Expression.New(constructor, keyValueExpression);
|
|
}
|
|
|
|
BinaryExpression assignPropertyValueExpression = Expression.Assign(body, keyValueExpression);
|
|
return Expression.Lambda<Action<TPropertyOwner, TProperty>>(assignPropertyValueExpression, thisParameter, propertyValueParameter);
|
|
}
|
|
|
|
static Expression<Func<TPropertyOwner, bool>> GetHasValueFunctionExpression<TPropertyOwner, TProperty>(Expression<Func<TPropertyOwner, TProperty>> getPropertyExpression) {
|
|
MemberExpression memberExpression = (MemberExpression)getPropertyExpression.Body;
|
|
if(IsNullableValueExpression(memberExpression)) {
|
|
Expression equalExpression = Expression.NotEqual(memberExpression.Expression, Expression.Constant(null));
|
|
return Expression.Lambda<Func<TPropertyOwner, bool>>(equalExpression, getPropertyExpression.Parameters.Single());
|
|
}
|
|
return x => true;
|
|
}
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Incapsulates operations to obtain and set the primary key value of a given entity.
|
|
/// </summary>
|
|
/// <typeparam name="TEntity">An owner type of the primary key property.</typeparam>
|
|
/// <typeparam name="TPrimaryKey">A primary key property type.</typeparam>
|
|
public class EntityTraits<TEntity, TPrimaryKey> {
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of EntityTraits class.
|
|
/// </summary>
|
|
/// <param name="getPrimaryKeyFunction">A function that returns the primary key value of a given entity.</param>
|
|
/// <param name="setPrimaryKeyAction">An action that assigns the primary key value to a given entity.</param>
|
|
/// <param name="hasPrimaryKeyFunction">A function that determines whether given the entity has a primary key assigned.</param>
|
|
public EntityTraits(Func<TEntity, TPrimaryKey> getPrimaryKeyFunction, Action<TEntity, TPrimaryKey> setPrimaryKeyAction, Func<TEntity, bool> hasPrimaryKeyFunction) {
|
|
this.GetPrimaryKey = getPrimaryKeyFunction;
|
|
this.SetPrimaryKey = setPrimaryKeyAction;
|
|
this.HasPrimaryKey = hasPrimaryKeyFunction;
|
|
}
|
|
|
|
/// <summary>
|
|
/// The function that returns the primary key value of a given entity.
|
|
/// </summary>
|
|
public Func<TEntity, TPrimaryKey> GetPrimaryKey { get; private set; }
|
|
|
|
/// <summary>
|
|
/// The action that assigns the primary key value to a given entity.
|
|
/// </summary>
|
|
public Action<TEntity, TPrimaryKey> SetPrimaryKey { get; private set; }
|
|
|
|
/// <summary>
|
|
/// A function that determines whether the given entity has a primary key assigned (the primary key is not null). Always returns true if the primary key is a non-nullable value type.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public Func<TEntity, bool> HasPrimaryKey { get; private set; }
|
|
}
|
|
}
|