Autofac命名实例 - 如果未找到则定义默认实例

时间:2017-10-31 14:26:43

标签: c# autofac named-instance

我使用Autofac注册命名实例。我必须将xml事务转换为对象。

首先,我有一个枚举。

public enum TransactionType
{
    Unknown = 0,
    [XmlNode("MyNodeA")]
    TypeA = 1,
    [XmlNode("MyNodeA")]
    TypeB = 2
}

我有一种方法可以使用枚举上的IDictionary<string, TransactionType>属性创建XmlNode

这是我的autofac映射

var mappings = TransactionTypeHelper.GetDictionary();

foreach (var mapping in mappings)
{
    builder.Register(ctx => {
                return mapping.Key;
    })
    .Named<TransactionType>(mapping.Value)
    .InstancePerLifetimeScope();
}

然后,我有一个TransactionTypeFactory来获取基于xml节点的TransactionType

public TransactionType GetTransactionType(string rootNode)
{
    return _container.Resolve<TransactionType>(rootNode?.ToLower());
}

我的问题是我想将任何未知的xml节点作为未知事务传递,以便我可以处理新事务而无需进行任何代码更改。问题是如果传入的节点尚未注册,则_container.Resolve会抛出错误。

我想要做的是,如果找不到命名实例而不是抛出错误,则autofac会返回枚举默认值。有趣的是,我有单元测试,这个容器被嘲笑,并且它们都通过了,但Autofac专门用尽了这个电话。

1 个答案:

答案 0 :(得分:0)

我知道这个问题比较老,但是我想分享我在此期间学到的解决方案,希望它可以帮助遇到相同问题的人。

使用autofac,您可以注册一个可以使用逻辑解析的函数。

首先,您将注册每个命名实例。在这个问题中,我是通过一个助手进行此操作并遍历一个集合,但是本质是将枚举的每个值映射到一个实例。

builder.Register<TransactionAClass>(ctx =>
{
    //get any instances required by ConcreteClass from the ctx here and pass into the constructor
    return new TransactionAClass();
})
.Named<Interfaces.ITransactionInterface>($"{TransactionType.TypeA:f}")
.InstancePerLifetimeScope();

所有注册后的已知值都将注册一个解析器功能。

builder.Register<Func<TransactionType, Interfaces.ITransactionInterface>>(ctx =>
{
    //you must resolve the context this way before being able to resolve other types
    var context = ctx.Resolve<IComponentContext>();

    //get the registered named instance
    return (type) =>
    { 
        var concrete = context.ResolveNamed<Interfaces.ITransactionInterface>($"{type:f}");

        if (concrete == null)
        {
            //return a default class or throw an exception if a valid registration is not found
            return new TransactionAClass();
        }

        return concrete;
    }
});

然后,您可以像这样使用解析器

public class MyClass
{
    private readonly ITransactionInterface transaction;

    public MyClass(Func<TransactionType, Interfaces.ITransactionInterface> transactionResolver)
    {
        transaction = transactionResolver.Invoke(TransactionType.TypeA);
    }
}