![](/img/trans.png)
[英]C#, Autofac: NamedParameter is not provided in Register<>
[英]AutoFac NamedParameter not resolving correctly
我在autofac中陷入困境,並且在綁定到特定構造函數時遇到一些問題。
我有以下代碼:
var builder = new ContainerBuilder();
builder
.RegisterType<GenericIocFactory>()
.As<IGenericIocFactory>();
builder
.RegisterType<Product>()
.As<IProduct>()
.PropertiesAutowired();
IContainer Container = builder.Build();
IGenericIocFactory Fac = Container.Resolve<IGenericIocFactory>();
_product = Fac.Get<IProduct>(new Dictionary<string,object>() { {"returnEmpty" , false} }) as Product;
然后在工廠:
public interface IGenericIocFactory
{
T Get<T>(Dictionary<string,object> options) where T: class;
}
public class GenericIocFactory : IGenericIocFactory
{
private readonly IComponentContext _icoContext;
private object _options;
public GenericIocFactory(IComponentContext icoContext,bool isInjected = true)
{
_icoContext= icoContext;
}
public T Get<T>(Dictionary<string,object> options) where T: class
{
var _parameters = new List<Parameter>();
foreach (var parameter in options)
{
_parameters.Add(new NamedParameter(parameter.Key, parameter.Value));
}
return _icoContext.Resolve<T>(_parameters);
//operate on new object
// tried this as well
//return _icoContext.Resolve<T>(
//new NamedParameter("returnEmpty" , false)
//new TypedParameter(typeof(bool),false)
//);
}
}
這樣可以解決產品,但不能解決我期望的構造函數。
目標構造函數
public Product(bool returnEmpty)
解決構造函數
public Product(IList<string> productCodes, string fields = "", string orderBy = "ProductCode")
總共有23個構造函數,一個解析不是最大的(所以我不認為它是貪婪的)
即
public Product(string strFields, string strFrom, string strFilter, string strOrderBy, string whseCode,
bool addExistsInWharehouse, string additionalAfterorderBy, bool forceUniqueRecords = false)
它也不是定義的第一個或最后一個。
我很沮喪,任何人都可以看到我做錯了什么。
不幸的是, Autofac不提供此機制。
您可能已經實現了IConstructorSelector
,當有多個構造函數可用時,它會選擇一個構造函數,並通過使用UsingSelector
方法將其設置為注冊,但是不幸的是,無法訪問當前解析操作的可用參數。
另一個解決方案是實現IInstanceActivator
,該實例負責根據類型和參數創建實例。 要使用自定義IInstanceActivator
,還需要實現IRegistrationBuilder
,這非常困難。 為了保證良好的性能,我還建議使用ConstructorParameterBinding
,它將使用動態編譯表達式創建優化的工廠。
如果您不能更改構造函數,那么我看到的唯一解決方案是實現自己的工廠。 由於您的對象沒有任何依賴關系,因此可以在不使用Autofac的情況下創建它們。
public class GenericIocFactory : IGenericIocFactory
{
public GenericIocFactory(ILifetimeScope scope)
{
this._scope = scope;
}
private readonly ILifetimeScope _scope;
public T Get<T>(params object[] args) where T: class
{
ConstructorInfo ci = this.GetConstructorInfo(args);
if (ci == null)
{
throw ...
}
var binder = new ConstructorParameterBinding(ci, args, this._scope);
T value = binder.Instanciate() as T;
if (value == null)
{
throw ...
}
if(value is IDisposable)
{
this._scope.Disposer.AddInstanceForDisposal(value);
}
return value;
}
protected virtual ConstructorInfo GetConstructorInfo<T>(params object[] args)
{
// TODO
}
}
因此,請再次閱讀Doco。 我需要在開始時綁定構造函數。 但這並不能解決我的問題,因此我每次請求一個實例時都會創建另一個容器,並根據參數構造它。 它有點不正確,但這對於任何正在過渡到使用autofac的現有解決方案的人來說,這都是一個現實的解決方案。
希望這對某人有幫助。
public interface IGenericIocFactory
{
T Get<T>(params object[] constructorParams) where T: class;
}
public interface ICustomAutoFacContainer
{
IContainer BindAndReturnCustom<T>(IComponentContext context, Type[] paramsList);
}
public class CustomAutoFacContainer : ICustomAutoFacContainer
{
public IContainer BindAndReturnCustom<T>(IComponentContext context, Type[] paramsList)
{
if (context.IsRegistered<T>())
{
// Get the current DI binding type target
var targetType = context
.ComponentRegistry
.Registrations
.First(r => ((TypedService) r.Services.First()).ServiceType == typeof(T))
.Target
.Activator
.LimitType;
// todo: exception handling and what not .targetType
var builder = new ContainerBuilder();
builder
.RegisterType(targetType)
.As<T>()
.UsingConstructor(paramsList)
.PropertiesAutowired();
return builder.Build();
}
return null;
}
}
public class GenericIocFactory : IGenericIocFactory
{
private ICustomAutoFacContainer _iCustomContainer;
private readonly IComponentContext _icoContext;
public GenericIocFactory(ICustomAutoFacContainer iCustomContainer, IComponentContext icoContext)
{
_iCustomContainer = iCustomContainer;
_icoContext = icoContext;
}
public T Get<T>(params object[] constructorParams) where T: class
{
//TODO handle reflection generation? ?? ?not needed?? ??
var parameters = constructorParams
.Select((t, index) => new PositionalParameter(index, t))
.Cast<Parameter>()
.ToList();
var parameterTypes = constructorParams
.Select((t, index) => t.GetType())
.ToArray();
return _iCustomContainer
.BindAndReturnCustom<T>(_icoContext,parameterTypes)
.Resolve<T>(parameters);
}
}
設置和用法如下所示:
var builder = new ContainerBuilder();
// Usually you're only interested in exposing the type
// via its interface:
builder
.RegisterType<GenericIocFactory>()
.As<IGenericIocFactory>();
builder
.RegisterType<CustomAutoFacContainer>()
.As<ICustomAutoFacContainer>();
builder
.RegisterType<Product>()
.As<IProduct>()
.PropertiesAutowired();
var container = builder.Build();
var factory = container.Resolve<IGenericIocFactory>();
_product = factory.Get<IProduct>(false) as Product;
_product = factory.Get<IProduct>("","") as Product;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.