C# 使用Castle Windsor在服务类的构造函数中使用参数化构造函数初始化类

C# 使用Castle Windsor在服务类的构造函数中使用参数化构造函数初始化类,c#,wcf,dependency-injection,castle-windsor,C#,Wcf,Dependency Injection,Castle Windsor,请注意,我已经更改了问题中的代码 请参阅下面的服务器端代码(WCF服务): servicerence1.GreetingServiceClient是一个服务引用 代码按照我的预期工作,即Castle Windsor允许我将问候语注入服务的构造函数中。但是,Greeting类本身有一个参数化构造函数(它需要一种语言)。在上面的代码中,我必须在服务的Say Hello方法中初始化问候语(使用语言)。如何在服务的构造函数中初始化问候语(使用语言)?提供运行时、用户驱动或其他动态依赖关系的一种主要方法*

请注意,我已经更改了问题中的代码

请参阅下面的服务器端代码(WCF服务):

servicerence1.GreetingServiceClient
是一个服务引用


代码按照我的预期工作,即Castle Windsor允许我将问候语注入服务的构造函数中。但是,Greeting类本身有一个参数化构造函数(它需要一种语言)。在上面的代码中,我必须在服务的
Say Hello
方法中初始化问候语(使用语言)。如何在服务的构造函数中初始化问候语(使用语言)?

提供运行时、用户驱动或其他动态依赖关系的一种主要方法*用于创建对象。Castle Windsor提供了几种不同的工具来帮助实现这一点,或者您可以使用内核并自己实现一个工厂

温莎的设施允许您提供工厂,这只是创建对象的方法。您可以在这里使用它,但在创建内容方面会失去一些灵活性(如果要将
ICalculator
的实现替换为其他类,则必须更新此方法)

为了获得最大的灵活性,您需要使用温莎的工厂。通过这些,您可以提供一个工厂接口,然后Windsor将自动生成该接口的实现

让我们以上面代码的简化版本为例。如果您刚刚拥有此对象:

public class Calculator : ICalculator
{
    string Operator;

    public Calculator(string operator)
    {
        Operator=operator;
    }
}
当您创建对象时,您希望传入
操作符
,您可以这样定义一个工厂:

public interface ICalculatorFactory
{
    ICalculator Create(string operator);
}
然后在安装程序中注册它:

kernel.Register(Component.For<ICalulatorFactory>().AsFactory());
请注意,
操作符的名称
参数很重要;默认情况下(如果需要,可以对此进行更改),Windsor按名称匹配参数

如果我们将您的
CalculatorService
类重新添加到组合中,您可以使用相同的模式:

public interface ICalculatorServiceFactory
{
    ICalculatorService Create(string operator);
}

public class CalculatorService : ICalculatorService
{
    private readonly ICalculator Calculator;

    public CalculatorService(string operator, ICalculatorFactory calculatorFactory)
    {
        Calculator=calculatorFactory.Create(operator);   
    }
}
但我真的不喜欢这样,因为为什么服务部门应该关心运营商是什么?这是计算器的一个细节。相反,将工厂更改为只接受
ICalculator
,并在创建此服务的位置将对象组合在一起:

public interface ICalculatorServiceFactory
{
    ICalculatorService Create(ICalculator calculator);
}

public class CalculatorService : ICalculatorService
{
    private readonly ICalculator Calculator;

    public CalculatorService(ICalculator calculator)
    {
        Calculator=calculator;
    }
}

public class CalculatorServiceUseExample
{
    public CalculatorServiceUseExample(ICalculatorServiceFactory calculatorServiceFactory, ICalculatorFactory calculatorFactory)
    {
        var addCalculator = calculatorFactory.Create("+");
        var service = calculatorServiceFactory.Create(addCalculator);

        // TODO: use the service
    }
}
使用这种模式有优点也有缺点,我将在后面介绍。一些优点是,您可以保护自己不受未来更改的影响,并避免使用服务定位器模式。缺点包括接口对象的激增和工厂的潜在病毒性使用(请参阅上面我的第一个解决方案,其中我们必须创建另一个工厂)

*当然还有其他方法,这只是我解决这个特殊情况的方法,因为对我来说,它表示意图,并且对于代码的读者来说是最容易发现的


根据您对WCF的编辑以及我所了解的您正在尝试的内容,我将按照如下方式实施服务合同:

public class CalculatorService : ICalculatorService
{
    private readonly ICalculatorFactory calculatorFactory;
    private ICalculator calculator;

    public CalculatorService(ICalculatorFactory calculatorFactory)
    {
        // store the factory until we need it
        this.calculatorFactory = calculatorFactory;
    }

    public void ChangeCalculatorServiceClient(string operator)
    {
        // A new operator, we'll need a new calculator
        calculator = calculatorFactory.Create(operator);
    }
}

好吧,你又一次改变了你的问题,加入了另一条皱纹;现在,您需要基于参数实例化不同的类型。你可以也应该继续使用工厂来实现这一点,我会这样做:

using Castle.Facilities.TypedFactory;

public class WindsorInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(
            Component.For<IGreeting, Greeting>(),
            Component.For<IGreetingFactory>().AsFactory(),
            Component.For<IGreetingService, GreetingService>(),
            Component.For<ILanguageFactory, LanguageFactory>());
    }
}

public interface ILanguageFactory
{
    ILanguage Create(string language);
}

public class LanguageFactory : ILanguageFactory
{
    private readonly IKernel kernel;

    public LanguageFactory(IKernel kernel)
    {
        this.kernel = kernel;
    }

    public ILanguage Create(string language)
    {
        switch (language)
        {
            case "S":
                return kernel.Resolve<Spanish>();
            default:
                throw new ArgumentException();
        }
    }
}

public class GreetingService : IGreetingService
{
    private readonly IGreetingFactory greetingFactory;
    private readonly ILanguageFactory languageFactory;
    private IGreeting greeting;

    public GreetingService(IGreetingFactory greetingFactory, ILanguageFactory languageFactory)
    {
        // store the factory until we need it
        this.greetingFactory = greetingFactory;
    }

    public string SayHello (string strLanguage)
    {
        var language = languageFactory.Create(strLanguage);
        greeting = greetingFactory.Create(language);
        return greeting.SayHello();
    }
}
使用Castle.Facilities.TypedFactory;
公共类WindsorInstaller:IWindsorInstaller
{
public void安装(IWindsorContainer、IConfigurationStore)
{
集装箱。登记(
Component.For(),
Component.For().AsFactory(),
Component.For(),
For());
}
}
公共接口ILanguageFactory
{
i语言创建(字符串语言);
}
公共类语言工厂:ILanguageFactory
{
私有只读IKernel内核;
公共语言工厂(IKernel内核)
{
this.kernel=内核;
}
公共ILanguage创建(字符串语言)
{
开关(语言)
{
案例“S”:
返回kernel.Resolve();
违约:
抛出新ArgumentException();
}
}
}
公共类迎宾服务:IGreetingService
{
私人只读IGreetingFactory-greetingFactory;
私有只读ILanguageFactory语言工厂;
私下问候;
公共迎宾服务(IGreetingFactory迎宾工厂、ILanguageFactory语言工厂)
{
//把工厂储存起来,直到我们需要它
this.greetingFactory=greetingFactory;
}
公共字符串SayHello(字符串strLanguage)
{
var language=languageFactory.Create(strLanguage);
greeting=greetingFactory.Create(语言);
回复问候语。SayHello();
}
}

操作符
不是关键字(例如:应该是
@operator
)。至于其他方面,我想我更愿意依赖一个包含用户输入的对象,并使用@Icepickle的可引用副本,对不起,我不知道你的意思。您能发布一个答案吗?@w0051977 duplicate answer清楚地显示了如何在注册期间将构造函数参数传递给dependency,所以解决了您的问题,不是吗?@Icepickle,谢谢。我看到了。但是,在这种情况下,参数是从配置文件获取的,即它不是从客户端传递的。谢谢,客户端的代码(带有WCF服务引用的windows窗体)是什么样子的?目前,我看不出它是如何将操作符传递给服务构造函数的。再次感谢。我不知道哪段代码是客户端代码,所以我不能说。你能解释一下这是如何回答我的问题的吗?您似乎正在初始化服务中的“Operator”变量。我询问如何将运算符变量从客户端(即windows窗体)传递到服务构造函数。这可能吗?对不起,如果我误解了。我仍然不知道这里的客户端代码是什么。您的问题没有提到WCF,因此此答案是作为单个流程解决方案编写的。你能举一个你想要的例子吗
public interface ICalculatorServiceFactory
{
    ICalculatorService Create(ICalculator calculator);
}

public class CalculatorService : ICalculatorService
{
    private readonly ICalculator Calculator;

    public CalculatorService(ICalculator calculator)
    {
        Calculator=calculator;
    }
}

public class CalculatorServiceUseExample
{
    public CalculatorServiceUseExample(ICalculatorServiceFactory calculatorServiceFactory, ICalculatorFactory calculatorFactory)
    {
        var addCalculator = calculatorFactory.Create("+");
        var service = calculatorServiceFactory.Create(addCalculator);

        // TODO: use the service
    }
}
public class CalculatorService : ICalculatorService
{
    private readonly ICalculatorFactory calculatorFactory;
    private ICalculator calculator;

    public CalculatorService(ICalculatorFactory calculatorFactory)
    {
        // store the factory until we need it
        this.calculatorFactory = calculatorFactory;
    }

    public void ChangeCalculatorServiceClient(string operator)
    {
        // A new operator, we'll need a new calculator
        calculator = calculatorFactory.Create(operator);
    }
}
using Castle.Facilities.TypedFactory;

public class WindsorInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(
            Component.For<IGreeting, Greeting>(),
            Component.For<IGreetingFactory>().AsFactory(),
            Component.For<IGreetingService, GreetingService>(),
            Component.For<ILanguageFactory, LanguageFactory>());
    }
}

public interface ILanguageFactory
{
    ILanguage Create(string language);
}

public class LanguageFactory : ILanguageFactory
{
    private readonly IKernel kernel;

    public LanguageFactory(IKernel kernel)
    {
        this.kernel = kernel;
    }

    public ILanguage Create(string language)
    {
        switch (language)
        {
            case "S":
                return kernel.Resolve<Spanish>();
            default:
                throw new ArgumentException();
        }
    }
}

public class GreetingService : IGreetingService
{
    private readonly IGreetingFactory greetingFactory;
    private readonly ILanguageFactory languageFactory;
    private IGreeting greeting;

    public GreetingService(IGreetingFactory greetingFactory, ILanguageFactory languageFactory)
    {
        // store the factory until we need it
        this.greetingFactory = greetingFactory;
    }

    public string SayHello (string strLanguage)
    {
        var language = languageFactory.Create(strLanguage);
        greeting = greetingFactory.Create(language);
        return greeting.SayHello();
    }
}