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