C# Autofac特性注入
我试图在Autofac中找到一种支持特定属性注入而不是整体属性注入的方法。Authound Autofac目前提供属性自动连接以支持整体属性注入,但在某些情况下,我只需要特定的属性注入(如NInject中使用的[Inject]属性) 在这里我发现了一个代码片段(PropertiesAutowired,由Alexandr Nikitin提供,谢谢!),代码可以支持特定的属性注入:C# Autofac特性注入,c#,dependency-injection,autofac,C#,Dependency Injection,Autofac,我试图在Autofac中找到一种支持特定属性注入而不是整体属性注入的方法。Authound Autofac目前提供属性自动连接以支持整体属性注入,但在某些情况下,我只需要特定的属性注入(如NInject中使用的[Inject]属性) 在这里我发现了一个代码片段(PropertiesAutowired,由Alexandr Nikitin提供,谢谢!),代码可以支持特定的属性注入: public static class PropertiesAutowiredExtensions { //
public static class PropertiesAutowiredExtensions
{
// Extension that registers only needed properties
// Filters by property name for simplicity
public static IRegistrationBuilder<TLimit, TReflectionActivatorData, TRegistrationStyle>
WithPropertiesAutowiredExcept<TLimit, TReflectionActivatorData, TRegistrationStyle>(
this IRegistrationBuilder<TLimit, TReflectionActivatorData, TRegistrationStyle> registrationBuilder,
params string[] propertiesNames)
where TReflectionActivatorData : ReflectionActivatorData
{
var type = ((IServiceWithType)registrationBuilder.RegistrationData.Services.Single()).ServiceType;
foreach (var property in type
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(pi => pi.CanWrite && !propertiesNames.Contains(pi.Name)))
{
// There's no additional checks like in PropertiesAutowired for simplicity
// You can add them from Autofac.Core.Activators.Reflection.AutowiringPropertyInjector.InjectProperties
var localProperty = property;
registrationBuilder.WithProperty(
new ResolvedParameter(
(pi, c) =>
{
PropertyInfo prop;
return pi.TryGetDeclaringProperty(out prop) &&
prop.Name == localProperty.Name;
},
(pi, c) => c.Resolve(localProperty.PropertyType)));
}
return registrationBuilder;
}
// From Autofac.Util.ReflectionExtensions
public static bool TryGetDeclaringProperty(this ParameterInfo pi, out PropertyInfo prop)
{
var mi = pi.Member as MethodInfo;
if (mi != null && mi.IsSpecialName && mi.Name.StartsWith("set_", StringComparison.Ordinal)
&& mi.DeclaringType != null)
{
prop = mi.DeclaringType.GetProperty(mi.Name.Substring(4));
return true;
}
prop = null;
return false;
}
}
公共静态类属性AutowiredExtrade
{
//只注册所需属性的扩展
//为简单起见,按属性名筛选
公共静态IRegistrationBuilder
具有属性AutowiredExcept(
此IRegistrationBuilder注册生成器,
参数字符串[]属性名称)
其中TReflectionActivatorData:ReflectionActivatorData
{
变量类型=((IServiceWithType)registrationBuilder.RegistrationData.Services.Single()).ServiceType;
类型中的foreach(var)属性
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(pi=>pi.CanWrite&&!propertiesNames.Contains(pi.Name)))
{
//为了简单起见,没有像Properties Autowired那样的附加检查
//您可以从Autofac.Core.Activators.Reflection.AutowiringPropertyInjector.InjectProperties添加它们
var localProperty=property;
registrationBuilder.WithProperty(
新解析参数(
(pi,c)=>
{
不动产不动产;
返回pi.TryGetDeclaringProperty(输出属性)&&
prop.Name==localProperty.Name;
},
(pi,c)=>c.Resolve(localProperty.PropertyType));
}
返回注册生成器;
}
//来自Autofac.Util.ReflectionExtensions
公共静态bool TryGetDeclaringProperty(此参数为INFO pi,out PropertyInfo prop)
{
var mi=pi.Member作为MethodInfo;
if(mi!=null&&mi.IsSpecialName&&mi.Name.StartWith(“set_”),StringComparison.Ordinal)
&&mi.DeclaringType!=null)
{
prop=mi.DeclaringType.GetProperty(mi.Name.Substring(4));
返回true;
}
prop=null;
返回false;
}
}
它在一般情况下运行良好。但当我在生命周期内使用这些代码时,它失败了:
using (var scope = container.BeginLifetimeScope(
builder => {
builder.RegisterInstance(SomeInstance).As<ISomeInstance>()
.WithPropertiesAutowired("Property1", "Property2"); }))
{
...
}
使用(var scope=container.BeginLifetimeScope(
生成器=>{
builder.RegisterInstance(SomeInstance.As())
.具有自动连接的属性(“属性1”、“属性2”);})
{
...
}
以下是错误消息:
The type 'Autofac.Builder.SimpleActivatorData' cannot be used as type parameter 'TReflectionActivatorData' in the generic type or method
'....AutofacHelpers.WithPropertiesAutowired<TLimit,TReflectionActivatorData,TRegistrationStyle>(
Autofac.Builder.IRegistrationBuilder<TLimit,TReflectionActivatorData,TRegistrationStyle>, params string[])'.
There is no implicit reference conversion from 'Autofac.Builder.SimpleActivatorData' to 'Autofac.Builder.ReflectionActivatorData'.
类型“Autofac.Builder.SimpleActivatorData”不能用作泛型类型或方法中的类型参数“TReflectionActivatorData”
“..AutofacHelpers.with Properties Autowired”(
Autofac.Builder.IRegistrationBuilder,参数字符串[])。
没有从“Autofac.Builder.SimpleActivatorData”到“Autofac.Builder.ReflectionActivatorData”的隐式引用转换。
似乎WithProperties Autowired只能在容器中使用,但不能用于LitfeTime范围。如何解决此问题?开箱即用,Autofac不允许您注册实例并在该实例上插入属性(如您所发现的) 从逻辑的角度来看,如果你有一个对象的实例,IoC框架应该能够假设它是完全构造的,并且它实际上是一个单例——毕竟,它是你正在注册的一个非常特定的实例通过尝试将实例与属性注入绑定,您可能会引入各种问题,如…
- 生存期范围不匹配-如果要向实例中注入每个实例或每个生存期范围属性值,则意味着属性值的寿命可能不会与实例/单例一样长
- 线程/竞态条件-如果不同线程中的两个事物解析实例,并且您在每个解析实例上注入属性,那么单例上的属性值将更改,并导致不一致的行为
lifetimeScope.InjectProperties(yourObjectInstance)
来注入所有属性;或者lifetimeScope.InjectUnsetProperties(yourObjectInstance)
只注入空/未设置的属性
如果需要进一步缩小范围,则需要创建自己的注入方法。您可以查看Autofac源代码,了解它是如何工作的,并相应地进行调整
- 是从生存期范围运行注入的扩展方法
- 是负责对属性执行实际注入的类