我使用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专门用尽了这个电话。
答案 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);
}
}