diff --git a/src/Autofac/RegistrationExtensions.cs b/src/Autofac/RegistrationExtensions.cs index 85eeb046f..c0b1a64b4 100644 --- a/src/Autofac/RegistrationExtensions.cs +++ b/src/Autofac/RegistrationExtensions.cs @@ -882,6 +882,35 @@ private static Type[] GetImplementedInterfaces(Type type) return registration.WithProperty(new NamedPropertyParameter(propertyName, propertyValue)); } + /// + /// Configure an explicit value for a property. + /// + /// Registration limit type. + /// Activator data type. + /// Registration style. + /// Type of the property being assigned. + /// Registration to set property on. + /// Expression of a property on the target type. + /// Value to supply to the property. + /// A registration builder allowing further configuration of the component. + public static IRegistrationBuilder + WithProperty( + this IRegistrationBuilder registration, + Expression> propertyExpression, + TProperty propertyValue) + where TReflectionActivatorData : ReflectionActivatorData + { + if (registration == null) throw new ArgumentNullException(nameof(registration)); + if (propertyExpression == null) throw new ArgumentNullException(nameof(propertyExpression)); + if (propertyValue == null) throw new ArgumentNullException(nameof(propertyValue)); + + var propertyInfo = (propertyExpression.Body as MemberExpression)?.Member as PropertyInfo; + if (propertyInfo == null) + throw new ArgumentOutOfRangeException(nameof(propertyExpression), RegistrationExtensionsResources.ExpressionDoesNotReferToProperty); + + return registration.WithProperty(new NamedPropertyParameter(propertyInfo.Name, propertyValue)); + } + /// /// Configure an explicit value for a property. /// diff --git a/src/Autofac/RegistrationExtensionsResources.Designer.cs b/src/Autofac/RegistrationExtensionsResources.Designer.cs index a71f7ffc9..1b0cd5b59 100644 --- a/src/Autofac/RegistrationExtensionsResources.Designer.cs +++ b/src/Autofac/RegistrationExtensionsResources.Designer.cs @@ -10,7 +10,6 @@ namespace Autofac { using System; - using System.Reflection; /// @@ -20,7 +19,7 @@ namespace Autofac { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class RegistrationExtensionsResources { @@ -40,7 +39,7 @@ internal class RegistrationExtensionsResources { internal static global::System.Resources.ResourceManager ResourceManager { get { if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Autofac.RegistrationExtensionsResources", typeof(RegistrationExtensionsResources).GetTypeInfo().Assembly); + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Autofac.RegistrationExtensionsResources", typeof(RegistrationExtensionsResources).Assembly); resourceMan = temp; } return resourceMan; @@ -70,6 +69,15 @@ internal class RegistrationExtensionsResources { } } + /// + /// Looks up a localized string similar to Expression does not refer to a property. + /// + internal static string ExpressionDoesNotReferToProperty { + get { + return ResourceManager.GetString("ExpressionDoesNotReferToProperty", resourceCulture); + } + } + /// /// Looks up a localized string similar to The instance registration '{0}' can support SingleInstance() sharing only.. /// diff --git a/src/Autofac/RegistrationExtensionsResources.resx b/src/Autofac/RegistrationExtensionsResources.resx index bb00ba61b..ba384f101 100644 --- a/src/Autofac/RegistrationExtensionsResources.resx +++ b/src/Autofac/RegistrationExtensionsResources.resx @@ -1,17 +1,17 @@  - @@ -135,4 +135,7 @@ You can only attach a registration predicate to a registration that has a callback container attached (e.g., one that was made with a standard ContainerBuilder extension method). - \ No newline at end of file + + Expression does not refer to a property + + diff --git a/test/Autofac.Test/ResolutionExtensionsTests.cs b/test/Autofac.Test/ResolutionExtensionsTests.cs index d05f87b3c..bfca9a0cc 100644 --- a/test/Autofac.Test/ResolutionExtensionsTests.cs +++ b/test/Autofac.Test/ResolutionExtensionsTests.cs @@ -1,7 +1,9 @@ -using Autofac.Core; +using System; +using Autofac.Core; using Autofac.Core.Activators.ProvidedInstance; using Autofac.Core.Registration; using Autofac.Test.Scenarios.Parameterisation; +using Autofac.Test.Scenarios.WithProperty; using Xunit; namespace Autofac.Test @@ -91,5 +93,33 @@ public void WhenPredicateAndValueParameterSupplied_PassedToComponent() Assert.Equal(a, result.A); Assert.Equal(b, result.B); } + + [Fact] + public void RegisterPropertyWithExpression() + { + const string a = "Hello"; + const bool b = true; + var builder = new ContainerBuilder(); + + builder.RegisterType() + .WithProperty(x => x.A, a) + .WithProperty(x => x.B, b); + + var container = builder.Build(); + var result = container.Resolve(); + + Assert.Equal(a, result.A); + Assert.Equal(b, result.B); + } + + [Fact] + public void RegisterPropertyWithExpressionFieldExceptions() + { + const string a = "Hello"; + var builder = new ContainerBuilder(); + + Assert.Throws(() => + builder.RegisterType().WithProperty(x => x._field, a)); + } } } diff --git a/test/Autofac.Test/Scenarios/WithProperty/WithProps.cs b/test/Autofac.Test/Scenarios/WithProperty/WithProps.cs new file mode 100644 index 000000000..eaf2eb6c5 --- /dev/null +++ b/test/Autofac.Test/Scenarios/WithProperty/WithProps.cs @@ -0,0 +1,11 @@ +namespace Autofac.Test.Scenarios.WithProperty +{ + public class WithProps + { + public string A { get; set; } + + public bool B { get; set; } + + public string _field; + } +}