【发布时间】:2019-08-21 17:08:49
【问题描述】:
我有一个发布/订阅队列,它返回我称之为 QueueMessages 的内容。
QueueMessage 有一个类型和一个正文。类型始终是字符串,但主体因类型而异。我希望继承类设置消息类型。我想添加我自己的本地属性来存储处理数据表。
我希望能够为 body 定义一个通用对象并在继承类中覆盖,但它失败了,因为我正在更改返回类型。
界面:
interface IBaseQueueMessage
{
Guid Id { get; set; }
string MessageType { get; }
object Message { get; set; }
DateTime ConsumeDate { get; set; }
}
基类:
public abstract class BaseQueueMessage:IBaseQueueMessage
{
public Guid Id { get; set; }
public abstract string MessageType { get; }
public abstract object Message { get; set; }
public DateTime ConsumeDate => DateTime.Now;
}
继承类(总共有 7 或 8 个不同的类)
public sealed class Type1Message: BaseCallType
{
public override string MessageType => "Type1Message";
public override Type1Message Message { get; set; }
}
public class Type1Message
{
public string aaa { get; set; }
public int bbb { get; set; }
}
public sealed class Type2Message: BaseCallType
{
public override string MessageType => "Type2Message";
public override Type2Message Message { get; set; }
}
public class Type2Message
{
public string aaa { get; set; }
public string bbb { get; set; }
public int ccc {get; set;}
public bool ddd {get; set;}
}
上述失败,因为我试图返回一个特定的类而不是通用对象。我明白为什么它会失败,但我想知道这样做的正确方法是什么?我可以只为每个类定义单独的类,然后用接口和继承来见鬼,但以这种方式处理它感觉不对。我打算将 QueueMessage 直接映射到每种不同类型的继承类,因此我希望模型与我从队列中获取的完全匹配。
为可能遗漏了一些非常明显的东西提前道歉,我已经有一段时间没有进行任何编码了,这对我来说是一个相对较新的领域。
已编辑以添加有关实施问题的更多详细信息
很多这样的作品,谢谢。我仍然有问题的地方是 MessageHandlerWrapper。如果我调试,则该方法尝试在_handler = handler 中使用的构造函数中的处理程序对象始终为空。
在我的 .net 核心 startup.cs 中,我有:
void RegisterHandler<TMessageType, THandler>()
where TMessageType : class
where THandler : IMessageHandler<TMessageType>
{
serviceCollection.AddSingleton<TMessageType>();
serviceCollection.AddSingleton(
serviceProvider => new MessageHandlerWrapper<TMessageType>(serviceProvider.GetService<THandler>(), serviceProvider)
);
}
...当我在上面提到的代码中调试时,依赖关系解决了该块末尾附近的...=> new MessageHandlerWrapper<...,所以我看不出为什么该服务不可用点。
有没有什么方法可以通过将服务解析到 MessageHandlerWrapper 中的具体处理程序来手动尝试调试它,以查看问题可能出在哪里?
为了完整起见,startup.cs 中的整个部分是:
//set up message handlers
var msgFactory = new MessageHandlerFactory();
//create local function to make it easier to add service references
void RegisterHandler<TMessageType, THandler>()
where TMessageType : class
where THandler : IMessageHandler<TMessageType>
{
serviceCollection.AddSingleton<TMessageType>();
serviceCollection.AddSingleton(
serviceProvider => new MessageHandlerWrapper<TMessageType>(serviceProvider.GetService<THandler>(), serviceProvider)
);
}
// Type1MessageHandler, etc is the implementation of IMessageHandler<Type1>
RegisterHandler<Type1, Type1MessageHandler>();
RegisterHandler<Type2, Type2MessageHandler>();
RegisterHandler<Type3, Type3MessageHandler>();
RegisterHandler<Type4, Type4MessageHandler>();
// some string constants for message types would be better.
serviceCollection.AddSingleton<IMessageHandlerFactory>(serviceProvider =>
{
msgFactory.RegisterHandler("Type1",
serviceProvider.GetService<MessageHandlerWrapper<Type1>>);
msgFactory.RegisterHandler("Type2",
serviceProvider.GetService<MessageHandlerWrapper<Type2>>);
msgFactory.RegisterHandler("Type3",
serviceProvider.GetService<MessageHandlerWrapper<Type3>>);
msgFactory.RegisterHandler("Type4",
serviceProvider.GetService<MessageHandlerWrapper<Type4>>);
return msgFactory;
});
serviceCollection.AddSingleton<IMessageHandler, MessageRouter>();
【问题讨论】:
-
根据您的接口声明,派生类必须返回类型
object。如果您愿意/能够修改接口以使其具有通用性,并且Message属性可以具有类型T(即接口类型参数),那么每个实现类都可以指定自己的类型。不幸的是,您的问题并不清楚这里有什么可能。 -
谢谢彼得。请按照您的建议如何更改界面中的消息类型?
-
查看标记重复的答案。您可能需要也可能不需要该答案中显示的非通用基本接口类型,具体取决于您的具体情况。
-
在某些时候你会需要消息处理程序。你是如何创造这些的?它们是从 IoC 容器中解析出来的吗?
-
尚不清楚这是否与您的情况相关,但我正在对通过网络传输的许多不同类型的消息做类似的事情。标头始终具有相同的格式,但每种消息类型的有效负载完全不同。我的
Message类有一个Memory<byte>和一个GetPayload<T>方法,其中T被限制为struct。消费者检查标头中的类型值并使用适当的类型参数调用GetPayload。
标签: c# class oop inheritance