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

w0051977

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

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

using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

using Castle.MicroKernel.Registration;
using Castle.MicroKernel.SubSystems.Configuration;
using Castle.Windsor;


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

    public interface ILanguage
    {
        string SayHello();
    }

    public class Spanish : ILanguage
    {
        public string SayHello()
        {
            return "Hola";
        }
    }

    public interface IGreeting
    {
        string SayHello();
    }

    public class Greeting: IGreeting
    {
        ILanguage Language;

        public Greeting (ILanguage language)
        {
            Language = language;
        }

        public string SayHello()
        {
            return Language.SayHello();
        }
    }

    public interface IGreetingFactory
    {
        IGreeting Create(ILanguage Language);
    }

    [ServiceContract]
    public interface IGreetingService
    {
        [OperationContract]
        string SayHello(string strLanguage);
    }

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

        public GreetingService()
        {
        }

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

        public string SayHello (string strLanguage)
        {
            if (strLanguage == "S")
            {
                ILanguage Language = new Spanish();
                Language = new Spanish();
                greeting = new Greeting(Language);
            }
            return greeting.SayHello();
        }

    }
}

和下面的客户端代码:

ServiceReference1.GreetingServiceClient s1 = new ServiceReference1.GreetingServiceClient();
            string greeting = s1.SayHello("S");

ServiceReference1.GreetingServiceClient 是服务参考。

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

帕特里克·奎克

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

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

为了获得最大的灵活性,您需要使用 Windsor 的基于接口的工厂。有了这些,您提供了一个工厂的接口,然后 Windsor 将自动生成它的实现。

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

public class Calculator : ICalculator
{
    string Operator;

    public Calculator(string operator)
    {
        Operator=operator;
    }
}

并且您想operator在创建对象时传入,您可以像这样定义一个工厂:

public interface ICalculatorFactory
{
    ICalculator Create(string operator);
}

然后你会在你的安装程序中注册它:

kernel.Register(Component.For<ICalulatorFactory>().AsFactory());

现在,在任何你想使用计算器的地方,你都可以为它注入一个工厂,然后调用Create

public class CalculatorUseExample
{
    private readonly ICalculator addCalculator;
    private readonly ICalculator subCalculator;

    public CalculatorUseExample(ICalculatorFactory calculatorFactory)
    {
        addCalculator = calculatorFactory.Create("+");
        subCalculator = calculatorFactory.Create("-");
    }
}

请注意,operator参数的名称很重要;默认情况下(您可以根据需要更改此设置),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();
    }
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

使用Castle Windsor将具有不同实现的列表的对象作为构造函数参数进行解析

来自分类Dev

如何指定我希望控制器的构造函数接收的类实例(使用Web API,DI和Castle Windsor时)?

来自分类Dev

使用Castle DynamicProxy初始化带有参数的构造函数

来自分类Dev

使用Castle DynamicProxy初始化带有参数的构造函数

来自分类Dev

Castle.Windsor使用Dapper实例化错误版本的SqlConnection

来自分类Dev

Castle.Windsor可以使用类型和名称来选择构造函数吗?

来自分类Dev

在Windows窗体应用程序中使用Castle Windsor

来自分类Dev

使用Castle Windsor在WebAPI中进行依赖注入

来自分类Dev

使用Castle Windsor在WebAPI中进行依赖注入

来自分类Dev

使用 Castle Windsor fluent API 注册实现多个接口的组件

来自分类Dev

使用 Castle Windsor 在 QueryBus 中查找查询处理程序

来自分类Dev

在<jsp:useBean>中使用构造函数初始化类

来自分类Dev

具有构造函数参数的Castle Windsor安装程序

来自分类Dev

如何在类构造函数中使用参数初始化std :: array的大小?

来自分类Dev

在初始化列表中使用空构造函数初始化父类?

来自分类Dev

在初始化列表中使用空构造函数初始化父类?

来自分类Dev

WPF ViewModel中的Castle Windsor构造函数注入

来自分类Dev

XML配置中的Castle Windsor服务覆盖

来自分类Dev

使用Castle-Windsor在MVC4中使用HttpClient的方式

来自分类Dev

使用构造函数初始化类中的指针

来自分类Dev

使用构造函数初始化类中的指针

来自分类Dev

为什么派生类的构造函数在初始化列表中使用基类的默认构造函数?

来自分类Dev

使用Castle Windsor和动态加载的DLL解析控制器

来自分类Dev

Castle Windsor-使用相同的通用工厂方法注册多个接口

来自分类Dev

如何使用 Castle Windsor 创建客户端版本 > 3.0.3660 的 RavenDB 会话?

来自分类Dev

使用 xml/app.config 在 Castle Windsor 中添加字符串列表

来自分类Dev

如何在C ++中使用构造函数(只是构造函数)在类中初始化大型私有数组?

来自分类Dev

如何使可以使用Typescript中的对象或常规参数构造函数初始化的类?

来自分类Dev

在类构造函数中使用重载>>运算符对其进行初始化

Related 相关文章

  1. 1

    使用Castle Windsor将具有不同实现的列表的对象作为构造函数参数进行解析

  2. 2

    如何指定我希望控制器的构造函数接收的类实例(使用Web API,DI和Castle Windsor时)?

  3. 3

    使用Castle DynamicProxy初始化带有参数的构造函数

  4. 4

    使用Castle DynamicProxy初始化带有参数的构造函数

  5. 5

    Castle.Windsor使用Dapper实例化错误版本的SqlConnection

  6. 6

    Castle.Windsor可以使用类型和名称来选择构造函数吗?

  7. 7

    在Windows窗体应用程序中使用Castle Windsor

  8. 8

    使用Castle Windsor在WebAPI中进行依赖注入

  9. 9

    使用Castle Windsor在WebAPI中进行依赖注入

  10. 10

    使用 Castle Windsor fluent API 注册实现多个接口的组件

  11. 11

    使用 Castle Windsor 在 QueryBus 中查找查询处理程序

  12. 12

    在<jsp:useBean>中使用构造函数初始化类

  13. 13

    具有构造函数参数的Castle Windsor安装程序

  14. 14

    如何在类构造函数中使用参数初始化std :: array的大小?

  15. 15

    在初始化列表中使用空构造函数初始化父类?

  16. 16

    在初始化列表中使用空构造函数初始化父类?

  17. 17

    WPF ViewModel中的Castle Windsor构造函数注入

  18. 18

    XML配置中的Castle Windsor服务覆盖

  19. 19

    使用Castle-Windsor在MVC4中使用HttpClient的方式

  20. 20

    使用构造函数初始化类中的指针

  21. 21

    使用构造函数初始化类中的指针

  22. 22

    为什么派生类的构造函数在初始化列表中使用基类的默认构造函数?

  23. 23

    使用Castle Windsor和动态加载的DLL解析控制器

  24. 24

    Castle Windsor-使用相同的通用工厂方法注册多个接口

  25. 25

    如何使用 Castle Windsor 创建客户端版本 > 3.0.3660 的 RavenDB 会话?

  26. 26

    使用 xml/app.config 在 Castle Windsor 中添加字符串列表

  27. 27

    如何在C ++中使用构造函数(只是构造函数)在类中初始化大型私有数组?

  28. 28

    如何使可以使用Typescript中的对象或常规参数构造函数初始化的类?

  29. 29

    在类构造函数中使用重载>>运算符对其进行初始化

热门标签

归档