/// <summary> /// Get activation configuration for strategy /// </summary> /// <param name="activationType"></param> /// <returns></returns> public override TypeActivationConfiguration GetActivationConfiguration(Type activationType) { var closedType = ReflectionHelper.CreateClosedExportTypeFromRequestingType(ActivationType, activationType); var configuration = ActivationConfiguration.CloneToType(closedType); return(configuration); }
/// <summary> /// Get activation configuration for strategy /// </summary> /// <param name="activationType"></param> /// <returns></returns> public override TypeActivationConfiguration GetActivationConfiguration(Type activationType) { var closedType = ReflectionHelper.CreateClosedExportTypeFromRequestingType(ActivationType, activationType); if (closedType != null) { return(ActivationConfiguration.CloneToType(closedType)); } return(base.GetActivationConfiguration(activationType)); }
public void TestConfig_Success() { var config = new ActivationConfiguration() .Configure <InheritedType4>(x => new InheritedType4(x.Prop1, x.Prop2, x.Prop3, x.Prop4)); var remute = new Remute(config); var instance = new InheritedType4("prop1", "prop2", "prop3", "prop4"); var actual = remute.With(instance, x => x.Prop1, "update"); Assert.AreEqual("update", actual.Prop1); Assert.AreEqual(instance.Prop2, actual.Prop2); Assert.AreEqual(instance.Prop3, actual.Prop3); Assert.AreEqual(instance.Prop4, actual.Prop4); }
public void ConfigureByExpression_Success() { var user = new User(1, "Joe", "Doe"); var config = new ActivationConfiguration() .Configure <User>(x => new User(x.FirstName, x.LastName)); var remute = new Remute(config); var actual = remute.With(user, x => x.FirstName, "Foo"); Assert.AreEqual("Foo", actual.FirstName); Assert.AreEqual(user.LastName, actual.LastName); Assert.AreEqual(default(int), actual.Id); }
private static ConstructorInfo FindConstructor(Type type, ActivationConfiguration activationConfiguration) { if (activationConfiguration.Settings.TryGetValue(type, out ActivationSetting setting)) { return(setting.Constructor); } var constructors = type.GetTypeInfo().DeclaredConstructors; if (constructors.Count() != 1) { throw new Exception($"Unable to find appropriate constructor of type '{type.Name}'. Consider to use {nameof(ActivationConfiguration)} parameter."); } return(constructors.Single()); }
public void ConfigureByExpression_InvalidProperty_Fail() { var user = new User(1, "Joe", "Doe"); try { var config = new ActivationConfiguration() .Configure <User>(x => new User("Foo", "Bar")); } catch (Exception ex) when(ex.Message == $"Parameter \"Foo\" must be a property of '{typeof(User)}'.") { return; } Assert.Fail(); }
public void ConfigureByExpression_InvalidExpression_Fail() { var user = new User(1, "Joe", "Doe"); try { var config = new ActivationConfiguration() .Configure <User>(x => x); } catch (Exception ex) when(ex.Message == $"Expression must specify constructor of '{typeof(User)}'.") { return; } Assert.Fail(); }
public void ConfigureByConstructor_Success() { var user = new User(1, "Joe", "Doe"); var type = user.GetType(); var constructor = type.GetConstructor(new[] { typeof(int), typeof(string), typeof(string) }); var config = new ActivationConfiguration() .Configure(constructor); var remute = new Remute(config); var actual = remute.With(user, x => x.FirstName, "Foo"); Assert.AreEqual("Foo", actual.FirstName); Assert.AreEqual(user.LastName, actual.LastName); Assert.AreEqual(user.Id, actual.Id); }
/// <summary> /// An extension method to simulate the "with" keyword from functional languages. An oversimplified description is that it creates a new instance of an immutable object with a specific value changed. /// </summary> /// <param name="expression">Expression returning the property to be mutated</param> /// <param name="value">The value the property is to be set to</param> /// <returns>A new instance of the object with the selected property set to the new value.</returns> public static TInstance With <TInstance, TValue>(this TInstance instance, Expression <Func <TInstance, TValue> > expression, TValue value) where TInstance : class { if (instance == null) { throw new ArgumentNullException(nameof(instance)); } if (expression == null) { throw new ArgumentNullException(nameof(expression)); } var activationConfiguration = new ActivationConfiguration(); var activationContextCache = new Dictionary <Type, ActivationContext>(); var result = value as object; var instanceExpression = expression.Body; while (instanceExpression is MemberExpression) { var propertyExpression = instanceExpression as MemberExpression; instanceExpression = propertyExpression.Expression; var property = propertyExpression.Member as PropertyInfo; if (property == null) { throw new Exception($"Unable to get property info for {propertyExpression.Member.Name} on type {typeof(TInstance).Name}. This is most likey because this was declared as a field and not a property."); } var type = property.DeclaringType; var activationContext = GetActivationContext(type, activationContextCache, activationConfiguration); var lambdaExpression = Expression.Lambda <Func <TInstance, object> >(instanceExpression, expression.Parameters); var compiledExpression = lambdaExpression.Compile(); var currentInstance = compiledExpression.Invoke(instance); var arguments = ResolveActivatorArguments(activationContext.ParameterResolvers, property, currentInstance, ref result); result = activationContext.Activator.Invoke(arguments); } return((TInstance)result); }
public void ConfigureByConstructorAndParameters_Success() { var user = new User(1, "Joe", "Doe"); var type = user.GetType(); var constructor = type.GetConstructor(new[] { typeof(string), typeof(string) }); var firstNameParameter = constructor.GetParameters().Single(x => x.Name == "firstNameNotMatchingPropertyName"); var firstNameProperty = type.GetProperty("FirstName"); var config = new ActivationConfiguration() .Configure(constructor, new Dictionary <ParameterInfo, PropertyInfo>() { [firstNameParameter] = firstNameProperty }); var remute = new Remute(config); var actual = remute.With(user, x => x.FirstName, "Foo"); Assert.AreEqual("Foo", actual.FirstName); Assert.AreEqual(user.LastName, actual.LastName); Assert.AreEqual(default(int), actual.Id); }
public void ConfigureByConstructorAndParameters_InvalidProperty_Fail() { var user = new User(1, "Joe", "Doe"); var constructor = user.GetType().GetConstructor(new[] { typeof(int), typeof(string), typeof(string) }); var firstNameParameter = constructor.GetParameters().Single(x => x.Name == "firstName"); var firstNameProperty = typeof(Employee).GetProperty("FirstName"); try { var config = new ActivationConfiguration() .Configure(constructor, new Dictionary <ParameterInfo, PropertyInfo>() { [firstNameParameter] = firstNameProperty }); } catch (Exception ex) when(ex.Message == $"Invalid property '{firstNameProperty.Name}'. Must be a member of '{constructor.DeclaringType}'.") { return; } Assert.Fail(); }
private static ActivationContext GetActivationContext(Type type, Dictionary <Type, ActivationContext> activationContextCache, ActivationConfiguration activationConfiguration) { if (activationContextCache.TryGetValue(type, out ActivationContext result)) { return(result); } var constructor = FindConstructor(type, activationConfiguration); var activator = GetActivator(constructor); var parameterResolvers = GetParameterResolvers(type, constructor, activationConfiguration); result = new ActivationContext(type, activator, parameterResolvers); activationContextCache[type] = result; return(result); }
private static ParameterResolver[] GetParameterResolvers(Type type, ConstructorInfo constructor, ActivationConfiguration activationConfiguration) { var properties = type.GetTypeInfo().DeclaredProperties.ToArray(); var parameters = constructor.GetParameters(); var parameterResolvers = new ParameterResolver[parameters.Length]; for (var i = 0; i < parameters.Length; i++) { var parameter = parameters[i]; var property = FindProperty(type, parameter, properties, activationConfiguration); var expressionParameter = Expression.Parameter(typeof(object)); var expressionParameterConvert = Expression.Convert(expressionParameter, type); var expressionProperty = Expression.Property(expressionParameterConvert, property); var expressionPropertyConvert = Expression.Convert(expressionProperty, typeof(object)); var lambda = Expression.Lambda <Func <object, object> >(expressionPropertyConvert, expressionParameter); var resolver = lambda.Compile(); var parameterResolver = new ParameterResolver(parameter, property, resolver); parameterResolvers[i] = parameterResolver; } return(parameterResolvers); }
private static PropertyInfo FindProperty(Type type, ParameterInfo parameter, PropertyInfo[] properties, ActivationConfiguration activationConfiguration) { if (activationConfiguration.Settings.TryGetValue(type, out ActivationSetting setting)) { if (setting.Parameters.TryGetValue(parameter, out PropertyInfo property)) { return(property); } } properties = properties.Where(x => string.Equals(x.Name, parameter.Name, StringComparison.OrdinalIgnoreCase)).ToArray(); if (properties.Count() != 1) { throw new Exception($"Unable to find appropriate property to use as a constructor parameter '{parameter.Name}'. Type '{type.Name}'. Consider to use {nameof(ActivationConfiguration)} parameter."); } return(properties.Single()); }