从通用类型工厂中挑选正确的组件

时间:2014-07-11 10:11:57

标签: c# generics castle-windsor typed-factory-facility

解决方案

请参阅@samy回答,但这是不正确的公开课。我只需要改变:

  StockDelayModule<T> : ModulePartBase<T>, IModulePart<T> where T : StockDelay

  StockDelayModule : ModulePartBase<StockDelay>, IModulePart<StockDelay>

然后在StockDelayModuleStockDelay

中对T的所有引用

然后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>(); 
}

然后我的工厂选择器正在运行,从GetComponentType覆盖DefaultTypedFactoryComponentSelector

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> { }

2 个答案:

答案 0 :(得分:1)

您不需要自定义解析程序,因为Castle会尝试根据返回类型解析工厂调用。除非您需要其他一些内容,否则以下内容应足以根据IModulePart<T>解析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
    }
}

答案 1 :(得分:0)

如果您尝试覆盖其他方法会发生什么:

  

protected override string GetComponentName(MethodInfo method,object [] arguments)

容器注册说什么?您可以使用配置错误的组件检查注册和部分。

虽然重写此方法可能部分解决了问题,但它无法解决问题的根源 - 这是检查组件配置是否错误的另一种方法。