代码之家  ›  专栏  ›  技术社区  ›  Josh

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

  •  1
  • Josh  · 技术社区  · 7 年前

    首先,我有一个枚举。

    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在这个调用中特别失败。

    1 回复  |  直到 7 年前
        1
  •  0
  •   Josh    5 年前

    我知道这个问题很老了,但我想和大家分享一下我在这期间学到的一个解决方案,希望它能帮助有同样问题的人。

    使用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);
        }
    }