问题
我有一个带有MessageType
字段的protobuf消息定义,这是一个枚举。鉴于传入的protobuf消息,我想基于IMessageHandler
从IoC容器中解析一些MessageType
。问题有两个:如何在编写MessageType
时表达IMessageHandler
约束,以及如何仅从IoC容器中解析所需的处理程序?
我正在使用Autofac,但我有兴趣听取任何容器的解决方案。
我的想法:
为了表达约束,我看到两个选项:属性或属性(不能使用泛型,因为它是枚举值)。我喜欢该属性,因为它使得在不指定约束的情况下编写IMessageHandler
是不可能的,但缺点是必须先实例化它才能看到属性值。
在我目前的代码中,我正在使用属性方法。我解决了所有IMessageHandler
并手动进行过滤,但似乎应该有更好的方法。并不是说我太担心性能,只是闻起来我正在解决那些不习惯的实例。
更新
为了让它更清晰一点,这就是我现在正在做的事情
public interface IMessageHandler
{
MessageType TargetType { get; }
void Handle(IMessage message);
}
public class SomeHandler : IMessageHandler
{
public MessageType TargetType
{
get { return MessageType.Type1; }
}
public void Handle(IMessage message)
{
// implementation
}
}
因此,当我收到protobuf消息时,我会解析所有IMessageHandler
并调用TargetType
与传入消息的MessageType
匹配的消息。
答案 0 :(得分:2)
我建议您使用autofac注册一个IMessageHandler-Factory类,并在该工厂上实现一个获取枚举的方法,并返回正确的IMessageHandler实现。
答案 1 :(得分:2)
我意识到Autofac's Keyed Services可以帮助我。我想我会采用这种方法。
MessageType
感兴趣的IMessageHandler
。IMessageHandler
MessageType
ResolveKeyed
仅获取我感兴趣的IMessageHandler
。好消息是,如果有人忘记使用该属性,我们可以在构建容器时捕获它。这是一个完整的例子。欢迎任何建议!
class Program
{
static IContainer container;
static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.RegisterAssemblyTypes(typeof(Program).Assembly)
.AssignableTo<IMessageHandler>()
.Keyed<IMessageHandler>(t => GetMessageType(t));
container = builder.Build();
InvokeHandlers(MessageType.Type1);
InvokeHandlers(MessageType.Type2);
Console.ReadKey();
}
static MessageType GetMessageType(Type type)
{
var att = type.GetCustomAttributes(true).OfType<MessageHandlerAttribute>().FirstOrDefault();
if (att == null)
{
throw new Exception("Somone forgot to put the MessageHandlerAttribute on an IMessageHandler!");
}
return att.MessageType;
}
static void InvokeHandlers(MessageType type)
{
using (var lifetime = container.BeginLifetimeScope())
{
// I'm impressed that Autofac knows what I mean here!
var handlers = lifetime.ResolveKeyed<IEnumerable<IMessageHandler>>(type);
foreach (var handler in handlers)
{
handler.Handle();
}
}
}
}
public enum MessageType
{
Type1,
Type2,
}
public interface IMessageHandler
{
void Handle();
}
public class MessageHandlerAttribute : Attribute
{
public MessageHandlerAttribute(MessageType messageType)
{
MessageType = messageType;
}
public MessageType MessageType { get; private set; }
}
[MessageHandler(MessageType.Type1)]
public class Handler1 : IMessageHandler
{
public void Handle()
{
Console.WriteLine("A handler for Type1");
}
}
[MessageHandler(MessageType.Type1)]
public class Handler2 : IMessageHandler
{
public void Handle()
{
Console.WriteLine("Another handler for Type1");
}
}
[MessageHandler(MessageType.Type2)]
public class Handler3 : IMessageHandler
{
public void Handle()
{
Console.WriteLine("A handler for Type2");
}
}