C# 从泛型工厂中选择正确的组件 解决方案

C# 从泛型工厂中选择正确的组件 解决方案,c#,generics,castle-windsor,typed-factory-facility,C#,Generics,Castle Windsor,Typed Factory Facility,请参见@samy-answer,但不正确的是开放类。我只需要改变一下: StockDelayModule<T> : ModulePartBase<T>, IModulePart<T> where T : StockDelay 根据T的不同,有几种不同的实现方式。例如: WebUrlModule<T> : IModulePart<T> where T : WebUrl StockDelayModule<T> : IMod

请参见@samy-answer,但不正确的是开放类。我只需要改变一下:

  StockDelayModule<T> : ModulePartBase<T>, IModulePart<T> where T : StockDelay
根据
T
的不同,有几种不同的实现方式。例如:

WebUrlModule<T> : IModulePart<T> where T : WebUrl
StockDelayModule<T> : IModulePart<T> where T : StockDelay

每件事看起来都非常正确,在调试(使用
WebUrl
)时,泛型类型类似于
IModulePart'1[[WebUrl,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null]

然而,正如您可能已经猜到的,它不起作用。如果我使用
StockDelay
调用,它可以很好地解决问题,因为我认为它返回的是第一个注册的组件,但是当使用
WebUrl
时,它会中断。我说
StockDelay
是有效的,但我认为这更像是返回任何东西(第一个匹配的组件),而不是选择正确的组件

我得到的信息是:
类型WebUrl不满足组件“StockDelayModule'1”的实现类型StockDelayModule'1的一般约束。这很可能是代码中的错误。

任何对任何人明显可见的东西,或任何可能不正确的建议?还是我只是在尝试一些不可能的事情!?谢谢


更新 如果我将类更改为抽象类,并使用非泛型的派生类实现它们,那么它就可以工作。所以我认为这只是castle中与泛型相关的一个小配置,这意味着它不能正确解析。想法?:

public class StockDelayModule : StockDelayModulePart<StockDelay> { }
public abstract class StockDelayModulePart<T> : ModulePartBase<T>, IModulePart<T> { }
公共类StockDelayModule:StockDelayModulePart{}
公共抽象类StockDelayModulePart:ModulePartBase,IModulePart{}

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

受保护的重写字符串GetComponentName(MethodInfo方法,对象[]参数)

集装箱登记怎么说?您可以检查注册和配置错误组件的部分


尽管重写此方法可能部分解决问题,但它并不能解决问题的根源——这是检查组件是否配置错误的另一种方法

您不需要自定义解析程序,因为Castle将根据返回类型尝试解析工厂调用。除非有其他需要,否则根据
T
,以下内容应足以解决
IModulePart

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
    }
}
公共类WebUrl{}
公共类StockDelay{}
公共接口IModulePart{}
公共类WebUrlModule:IModulePart{}
公共类StockDelayModule:IModulePart{}
公共接口IModulePartFactory
{
IModulePart FindModulePartFor();
}
内部课程计划
{
私有静态void Main(字符串[]args)
{
var container=newcastle.Windsor.WindsorContainer();
container.AddFacility();
集装箱。登记(
类。FromAssemblyInThisApplication()的
.BasedOn(类型(部分))
.WithService.Base()
.生活方式,
Component.For().AsFactory()
);
var factory=container.Resolve();
var moduleForWebUrl=factory.FindModulePartFor();
//类型为WebUrlModule
var moduleForStockDelay=factory.FindModulePartFor();
//类型为StockDelayModule
}
}

如果我将我的安装程序更改为
命名为
并带有实现名称,删除'1-so
WebUrlModule
,然后使用
GetComponentName
和通用参数name+“Module”进行解析,它会起作用,但我并不喜欢这种方法。请从组件选择器粘贴代码好吗?因为应该有选择合适组件的逻辑。这与我已经说过的差不多,但我会更新我的问题。我已经尝试过这条路线,似乎没有什么不同。它仍然解析不正确的组件。这是一个“潜在的配置错误的组件”,但我认为这是因为它比其他任何东西都有动态参数。但是,正如我在我的问题上添加(编辑)的那样,创建我的类的非泛型派生类很好…:-/您是对的,在使用派生类时,它只使用
AsFactory()
,而不使用我的自定义组件选择器(请参阅我的更新),但是,当直接使用泛型类时,我仍然有相同的错误-
类型WebUrl不满足组件StockDelayModulePart'1的实现类型StockDelayModulePart'1的泛型约束。这很可能是您的代码中的一个bug。
您能在一个块中向我们展示整个类/接口/注册/解析代码吗?我有一种感觉,我们缺少了一部分,最明显的是
ModulePartbase
。使用符号
WebUrlModule:IModulePart,其中T:WebUrl
应该是
WebUrlModule:IModulePart
ModulePartBase
只是一个基类,作为创建
IResponse
IPromise
的助手。然而,我刚刚从您所说的内容中意识到,我不需要我的派生类是开放的,我已经删除了它以及基和接口(以及类中的引用)上的泛型,并且一切正常。谢谢你的帮助。我应该先提到它,但我不想在重新编程之前先假定你的代码;通常情况下,人们会在发布之前对代码进行清理,这可能会导致小的不一致。很高兴这能帮上忙!
 Classes.FromAssemblyInDirectory(new AssemblyFilter("bin"))
                .BasedOn(typeof(IModulePart<>))                   
                .WithService.Base()
                .LifestyleTransient()
public interface IModulePartFactory
{
    IModulePart<T> FindModulePartFor<T>(); 
}
protected override Type GetComponentType(MethodInfo method, object[] arguments)
{
    if (method.Name == "FindModulePartFor")
    {
         return typeof(IModulePart<>).MakeGenericType(method.GetGenericArguments()[0]);
    }

    return base.GetComponentType(method, arguments);
}
public class StockDelayModule : StockDelayModulePart<StockDelay> { }
public abstract class StockDelayModulePart<T> : ModulePartBase<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
    }
}