-
-
Save nazrhyn/31e4c46cdfbd9865f5a0 to your computer and use it in GitHub Desktop.
This file contains 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
/// <summary> | |
/// Registers a property with an initial value and a changed value. | |
/// </summary> | |
/// <typeparam name="TProperty">The type of the property.</typeparam> | |
/// <param name="property">A lambda expression indicating what property to register to.</param> | |
/// <param name="initialValue">The initial value of the property.</param> | |
/// <param name="changedValue">The value to change the property to.</param> | |
protected void RegisterPropertyMutation<TProperty>(Expression<Func<TEntity, TProperty>> property, TProperty initialValue, TProperty changedValue) | |
{ | |
// check property expression composition | |
ValidatePropertyExpression(property); | |
// Func<TEntity, TProperty> guarantees one parameter to the lambda | |
ParameterExpression getEntityParam = property.Parameters[0]; | |
// construct the equivalent of this -or- this | |
// object Method(TEntity entity) e => (object)e.Property; | |
// { | |
// return (object)entity.Property; | |
// } | |
Expression<Func<TEntity, object>> boxedPropertyGet = Expression.Lambda<Func<TEntity, object>>( | |
Expression.Convert( // performs the cast from TProperty to object; the result of this is implicitly returned (one-line lambda) | |
property.Body, | |
typeof(object) | |
), | |
getEntityParam // uses the same parameter as before | |
); | |
// create the parameters for the Action<TEntity, object> | |
ParameterExpression setEntityParam = property.Parameters[0]; // we have to re-use this one as we're re-using the body | |
ParameterExpression setBoxedValueParam = Expression.Parameter(typeof(object), "setBoxedValueParam"); // the input is now object | |
// construct the equivalent of | |
// void Method(TEntity entity, object value) | |
// { | |
// entity.Property = (TProperty)value; | |
// } | |
Expression<Action<TEntity, object>> boxedPropertySet = Expression.Lambda<Action<TEntity, object>>( | |
Expression.Assign( // performs the assign from the cast value to the property access | |
property.Body, // the property access copied from the original | |
Expression.Convert( // performs the convert from the object input to the type of the property | |
setBoxedValueParam, | |
typeof(TProperty) | |
) | |
), // the lambda takes two parameters | |
setEntityParam, // the entity, as before | |
setBoxedValueParam // and the value, boxed to object | |
); | |
RegisterPropertyMutation( | |
new PropertyValueMutation | |
{ | |
PropertyName = GetFullPropertyPath(property), | |
PropertyGet = boxedPropertyGet.Compile(), | |
PropertySet = boxedPropertySet.Compile(), | |
InitialValue = initialValue, | |
ChangedValue = changedValue | |
} | |
); | |
} | |
/// <summary> | |
/// Registers a property with an initial value and a changed value and a method by which the property should be assigned. | |
/// </summary> | |
/// <typeparam name="TProperty">The type of the property.</typeparam> | |
/// <param name="property">A lambda expression indicating what property to register to.</param> | |
/// <param name="initialValue">The initial value of the property.</param> | |
/// <param name="changedValue">The value to change the property to.</param> | |
/// <param name="propertySet">An expression that will be used to assign the property value in a non-standard way.</param> | |
protected void RegisterPropertyMutation<TProperty>(Expression<Func<TEntity, TProperty>> property, TProperty initialValue, TProperty changedValue, Expression<Action<TEntity, TProperty>> propertySet) | |
{ | |
// check property expression composition | |
ValidatePropertyExpression(property); | |
// Func<TEntity, TProperty> guarantees one parameter to the lambda | |
ParameterExpression getEntityParam = property.Parameters[0]; | |
// construct the equivalent of this -or- this | |
// object Method(TEntity entity) e => (object)e.Property; | |
// { | |
// return (object)entity.Property; | |
// } | |
Expression<Func<TEntity, object>> boxedPropertyGet = Expression.Lambda<Func<TEntity, object>>( | |
Expression.Convert( // performs the cast from TProperty to object; the result of this is implicitly returned (one-line lambda) | |
property.Body, | |
typeof(object) | |
), | |
getEntityParam // uses the same parameter as before | |
); | |
// Action<TEntity, TProperty> guarantees two parameters to the lambda | |
ParameterExpression setEntityParam = propertySet.Parameters[0]; | |
ParameterExpression setTypedValueParam = propertySet.Parameters[1]; | |
// create a new object parameter for the new lambda | |
ParameterExpression setBoxedValueParam = Expression.Parameter(typeof(object), "setBoxedValueParam"); | |
// construct the equivalent of | |
// void Method(TEntity entity, object value) | |
// { | |
// TProperty typed = (TProperty)value; | |
// <original-body>(entity, typed); | |
// } | |
Expression<Action<TEntity, object>> boxedPropertySet = Expression.Lambda<Action<TEntity, object>>( | |
Expression.Block( // contains the variable assignment and the original body | |
new[] { setTypedValueParam }, // declares the typed variable as in scope for this body | |
Expression.Assign( // performs the assignment to the typed variable | |
setTypedValueParam, | |
Expression.Convert( // performs the cast from object to TProperty for assignment to the typed variable | |
setBoxedValueParam, | |
typeof(TProperty) | |
) | |
), | |
propertySet.Body // copies the old body that already uses the typed variable for the assignment | |
), | |
setEntityParam, // redefines the parameters to the action as the previous entity parameter | |
setBoxedValueParam // and a new object-type parameter that we un-box above | |
); | |
RegisterPropertyMutation( | |
new PropertyValueMutation | |
{ | |
PropertyName = GetFullPropertyPath(property), | |
PropertyGet = boxedPropertyGet.Compile(), | |
PropertySet = boxedPropertySet.Compile(), | |
InitialValue = initialValue, | |
ChangedValue = changedValue | |
} | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment