private InitExpressionResult <Func <T, T, T> > CreateCoalesceWith( ConstructorInfo constructor) { var readableProperties = new List <PropertyInfo>( from p in typeof(T).GetRuntimeProperties() where p.CanRead select p); var readonlyProperties = new HashSet <PropertyInfo>( from p in readableProperties where false == p.CanWrite select p); var settableProperties = new HashSet <PropertyInfo>( from p in readableProperties where p.CanWrite select p); ParameterExpression left = Parameter(typeof(T), nameof(left)); ParameterExpression right = Parameter(typeof(T), nameof(right)); var arguments = new List <Expression>(); foreach (ParameterInfo parameter in constructor.GetParameters()) { PropertyInfo property = PickParameterMatch(readonlyProperties, parameter) ?? PickParameterMatch(settableProperties, parameter); if (property == null) { InitExpressionError error = GetNoPropertyMatchesParameterError( constructor, parameter); return(InitExpressionResult <Func <T, T, T> > .WithError(error)); } arguments.Add(CoalesceOrMemberAccess(property, left, right)); } if (readonlyProperties.Any()) { InitExpressionError error = GetPropertyCannotBeSetError( constructor, readonlyProperties); return(InitExpressionResult <Func <T, T, T> > .WithError(error)); } MemberInitExpression memberInitExpression = MemberInit( New(constructor, arguments), from property in settableProperties select Bind( property, CoalesceOrMemberAccess(property, left, right))); Expression <Func <T, T, T> > lambdaExpression = Lambda <Func <T, T, T> >(memberInitExpression, left, right); return(new InitExpressionResult <Func <T, T, T> >(lambdaExpression)); }
private static Func <TModel, TModel, TModel> BuildImplementor() { var factory = new InitExpressionFactory <TModel>(); InitExpressionResult <Func <TModel, TModel, TModel> > result = factory.CreateCoalesce(); return((newValue, lastValue) => { var coalescable = newValue as ICoalescable <TModel>; if (coalescable != null) { return coalescable.Coalesce(lastValue); } if (false == result.IsSuccess) { var message = string.Join( Environment.NewLine, from error in result.Errors select error.GetExceptionMessage()); throw new InvalidOperationException(message); } return result.Function.Invoke(newValue, lastValue); }); }
public InitExpressionResult <Func <T, T, T> > CreateCoalesce() { IEnumerable <ConstructorInfo> constructors = typeof(T).GetTypeInfo().DeclaredConstructors; var results = new List <InitExpressionResult <Func <T, T, T> > >( from constructor in constructors orderby constructor.GetParameters().Length descending select CreateCoalesceWith(constructor)); return(results.FirstOrDefault(r => r.IsSuccess) ?? InitExpressionResult <Func <T, T, T> > .WithErrors( from r in results from e in r.Errors select e)); }