从泛型工厂中选择正确的组件
本文关键字:组件 选择 泛型 工厂 | 更新日期: 2023-09-27 18:12:32
解决方案
见@samy的答案,但是开放类是不正确的。我只需要修改:
StockDelayModule<T> : ModulePartBase<T>, IModulePart<T> where T : StockDelay
StockDelayModule : ModulePartBase<StockDelay>, IModulePart<StockDelay>
则StockDelayModule
中对T的所有引用都指向StockDelay
AsFactory()
注册然后工作良好,可以解决正确的组件。
我一直不愿意发布这个问题,因为我想弄清楚它,但我也不想看到一连串的"重复"评论,但我很困惑。
我有一个接口
public interface IModulePart<T>
{
IResponse<T> Create(CreateRequest request, IPromise<T> promise);
IResponse Delete(DeleteRequest request, IPromise<T> promise);
IResponse<T> Read(ReadRequest request, IPromise<T> promise);
IResponse<T> Update(UpdateRequest request, IPromise<T> promise);
}
具有基于T
的不同实现。例如:
WebUrlModule<T> : IModulePart<T> where T : WebUrl
StockDelayModule<T> : IModulePart<T> where T : StockDelay
我已经有了我的安装程序,它正在注册组件:
Classes.FromAssemblyInDirectory(new AssemblyFilter("bin"))
.BasedOn(typeof(IModulePart<>))
.WithService.Base()
.LifestyleTransient()
我有我的工厂:
public interface IModulePartFactory
{
IModulePart<T> FindModulePartFor<T>();
}
然后我的工厂选择器正在运行,从DefaultTypedFactoryComponentSelector
重写GetComponentType
:
protected override Type GetComponentType(MethodInfo method, object[] arguments)
{
if (method.Name == "FindModulePartFor")
{
return typeof(IModulePart<>).MakeGenericType(method.GetGenericArguments()[0]);
}
return base.GetComponentType(method, arguments);
}
似乎所有的看起来都是正确的,当调试(使用WebUrl
)时,泛型类型类似于IModulePart'1[[WebUrl, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]
然而,正如你可能已经猜到的那样,它不起作用。如果我使用StockDelay
进行调用,它会解决得很好,因为我认为它返回了第一个注册的组件,但是当使用WebUrl
时,它会中断。我说StockDelay
工作,但我认为这更只是情况下,它返回任何东西(第一个匹配组件),而不是选择正确的组件。
我得到的消息是:Types WebUrl don't satisfy generic constraints of implementation type StockDelayModule'1 of component 'StockDelayModule'1'. This is most likely a bug in your code.
任何对任何人来说都很明显的东西,或者对任何可能不正确的东西的建议?或者我只是在尝试一些不可能的事情!?谢谢。
更新
如果我改变我的类抽象和实现他们与派生类,不是泛型它的工作。所以这让我认为这只是一个小的配置在城堡相关的通用,这意味着它没有正确地解决。想法吗?:
public class StockDelayModule : StockDelayModulePart<StockDelay> { }
public abstract class StockDelayModulePart<T> : ModulePartBase<T>, IModulePart<T> { }
您不需要自定义解析器,因为Castle将尝试根据返回类型解析工厂调用。除非您需要其他一些东西,否则根据T
,以下内容应该足以解决IModulePart<T>
:
public class WebUrl { }
public class StockDelay { }
public interface IModulePart<T> { }
public class WebUrlModule : IModulePart<WebUrl> { }
public class StockDelayModule : IModulePart<StockDelay> { }
public interface IModulePartFactory
{
IModulePart<T> FindModulePartFor<T>();
}
internal class Program
{
private static void Main(string[] args)
{
var container = new Castle.Windsor.WindsorContainer();
container.AddFacility<TypedFactoryFacility>();
container.Register(
Classes.FromAssemblyInThisApplication()
.BasedOn(typeof(IModulePart<>))
.WithService.Base()
.LifestyleTransient(),
Component.For<IModulePartFactory>().AsFactory()
);
var factory = container.Resolve<IModulePartFactory>();
var moduleForWebUrl = factory.FindModulePartFor<WebUrl>();
// type is WebUrlModule
var moduleForStockDelay = factory.FindModulePartFor<StockDelay>();
// type is StockDelayModule
}
}
如果尝试重写其他方法会发生什么:
protected override string GetComponentName(MethodInfo方法,object[] arguments)
集装箱注册说明?您可以检查注册和错误配置组件的部分。
虽然重写此方法可能部分解决问题,但不能解决问题的根源-这是检查您是否错误配置组件的另一种方法。