如何在autofac聚合服务中按属性名称区分注册?

时间:2018-10-18 02:31:51

标签: state autofac

  
interface IState {

}

class GoodState: IState {}
class BadState: IState {}
class MoreState: IState {}

// I stuck at here... :(
interface StateAggregateService {
  IState GoodState {get;}
  IState BadState {get;}
  IState MoreState {get;}
}

基本上,我想实现状态机模式。我想使用 autofac聚合服务扩展名自动为我创建一个工厂类。但是所有具体的状态类都继承自IState接口,聚合服务扩展无法区分它们。

一种解决方法是定义一些虚拟接口,例如IGoodState,该接口继承自IState。问题在于,随着状态类数量的增加,虚拟接口数量的增加,我觉得这确实是一个愚蠢的主意。

是否可以将注册与属性名称相关联?

1 个答案:

答案 0 :(得分:0)

一种方法是对您的IState实现使用命名注册,对实现IStateAggregateService的类使用属性注入。因此,对于聚合服务,您将:

interface IStateAggregateService
{
    IState GoodState { get; }
    IState BadState { get; }
    IState MoreState { get; }
}

class StateAggregateService : IStateAggregateService
{
    public IState GoodState { get; set; }
    public IState BadState { get; set; }
    public IState MoreState { get; set; }
}

,注册如下所示:

builder.RegisterType<GoodState>().Named<IState>("GoodState");
builder.RegisterType<BadState>().Named<IState>("BadState");
builder.RegisterType<MoreState>().Named<IState>("MoreState");

builder.Register(c => new StateAggregateService
    {
        GoodState = c.ResolveNamed<IState>("GoodState"),
        BadState = c.ResolveNamed<IState>("BadState"),
        MoreState = c.ResolveNamed<IState>("MoreState")
    }).As<IStateAggregateService>();

请记住,这种方法每次在聚合服务中调用属性时都会返回相同的对象。

如果您每次调用属性都需要新的实例,则可以使用具有键注册IIndex<TKey, TService>界面的其他方法;注册看起来像这样:

builder.RegisterType<GoodState>().Keyed<IState>("GoodState");
builder.RegisterType<BadState>().Keyed<IState>("BadState");
builder.RegisterType<MoreState>().Keyed<IState>("MoreState");

builder.RegisterType<StateAggregateService>().As<IStateAggregateService>();

服务的实现

class StateAggregateService : IStateAggregateService
{
    private readonly IIndex<string, IState> _states;

    public IState GoodState => _states["GoodState"];
    public IState BadState => _states["BadState"];
    public IState MoreState => _states["MoreState"];

    public StateAggregateService(IIndex<string, IState> states)
    {
        _states = states;
    }
}

为使此方法更简洁,您可能希望使用一些枚举作为IState实现的键,而不是string

此外,您可以摆脱StateAggregateService并在需要的地方使用IIndex<TKey, TService>作为工厂。

更新: 如评论中所述,的确,使用聚合服务无法实现您需要的解决方案。但是可以通过一些手动配准和反射来做类似的事情。对于以下接口和聚合器类:

interface IStateAggregateService
{
    IState GoodState { get; }
    IState BadState { get; }
    IState MoreState { get; }
}

class StateAggregateService : IStateAggregateService
{
    public IState GoodState { get; set; }
    public IState BadState { get; set; }
    public IState MoreState { get; set; }
}

您可以使用以下注册:

builder.RegisterType<GoodState>().Keyed<IState>("GoodState");
builder.RegisterType<BadState>().Keyed<IState>("BadState");
builder.RegisterType<MoreState>().Keyed<IState>("MoreState");

builder.Register(c =>
    {
        var serviceProps = typeof(StateAggregateService).GetProperties();

        var service = new StateAggregateService();
        foreach (var property in serviceProps)
        {
            property.SetValue(service, c.ResolveKeyed<IState>(property.Name));
        }

        return service;
    }).As<IStateAggregateService>();

区别在于您需要创建一个实现您的聚合接口的类。此解决方案使用属性名称,因此您需要将其名称与类型保持相同,或准备自己的逻辑以将适当的实现分配给聚合器属性。