1

我正在使用 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用于获取TransactionType基于 xml 节点的方法。

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

我的问题是我想将任何未知的 xml 节点作为未知事务传递,这样我就可以在不更改任何代码的情况下处理新事务。问题是_container.Resolve如果传入的节点尚未注册,则会引发错误。

如果找不到命名实例而不是抛出错误,我想要做的是让 autofac 返回枚举默认值。有趣的是,我对这个容器进行了单元测试,并且它们都通过了,但是 Autofac 在这个调用上特别失败了。

4

1 回答 1

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);
    }
}
于 2019-08-30T13:40:06.600 回答