解决MySql布尔型新旧版本兼容问题,采用枚举来表示布尔型的数据表。由正向工程赋值
大石头 authored at 2018-05-15 21:21:05
5.21 KiB
X
using NewLife.Data;
using NewLife.Reflection;

namespace NewLife.Messaging;

/// <summary>消息命令接口</summary>
/// <remarks>
/// 消息接口定义了请求-响应模式的基本消息结构:
/// <list type="bullet">
/// <item><description><see cref="Reply"/>:标识消息方向,请求或响应</description></item>
/// <item><description><see cref="Error"/>:标识处理状态,成功或失败</description></item>
/// <item><description><see cref="OneWay"/>:标识通信模式,单向或双向</description></item>
/// <item><description><see cref="Payload"/>:消息负载数据</description></item>
/// </list>
/// 实现类应保证线程安全性,特别是在消息池化复用场景。
/// </remarks>
public interface IMessage : IDisposable
{
    /// <summary>是否响应。为true表示这是响应消息,为false表示这是请求消息</summary>
    Boolean Reply { get; set; }

    /// <summary>是否有错。为true表示处理过程中发生错误</summary>
    Boolean Error { get; set; }

    /// <summary>单向请求。为true表示不需要等待响应</summary>
    Boolean OneWay { get; set; }

    /// <summary>负载数据。消息的实际内容</summary>
    IPacket? Payload { get; set; }

    /// <summary>根据请求创建配对的响应消息</summary>
    /// <remarks>
    /// 响应消息会继承请求消息的序列号等关键属性,用于请求-响应匹配。
    /// 仅请求消息可调用此方法,响应消息调用将抛出异常。
    /// </remarks>
    /// <returns>响应消息实例</returns>
    /// <exception cref="InvalidOperationException">当在响应消息上调用时抛出</exception>
    IMessage CreateReply();

    /// <summary>从数据包中读取消息</summary>
    /// <param name="pk">原始数据包</param>
    /// <returns>是否成功解析</returns>
    Boolean Read(IPacket pk);

    /// <summary>把消息转为封包</summary>
    /// <returns>序列化后的数据包</returns>
    IPacket? ToPacket();
}

/// <summary>消息命令基类</summary>
/// <remarks>
/// 提供 <see cref="IMessage"/> 接口的基础实现,支持:
/// <list type="bullet">
/// <item><description>基本的请求/响应/错误/单向标志位</description></item>
/// <item><description>负载数据的透传</description></item>
/// <item><description>资源释放(回收数据包到内存池)</description></item>
/// </list>
/// 子类可重写 <see cref="Read"/> 和 <see cref="ToPacket"/> 实现自定义协议格式。
/// </remarks>
public class Message : IMessage
{
    #region 属性
    /// <summary>是否响应。为true表示这是响应消息,为false表示这是请求消息</summary>
    public Boolean Reply { get; set; }

    /// <summary>是否有错。为true表示处理过程中发生错误</summary>
    public Boolean Error { get; set; }

    /// <summary>单向请求。为true表示不需要等待响应</summary>
    public Boolean OneWay { get; set; }

    /// <summary>负载数据。消息的实际内容</summary>
    public IPacket? Payload { get; set; }
    #endregion

    #region 构造
    /// <summary>销毁。回收数据包到内存池</summary>
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    /// <summary>释放资源</summary>
    /// <param name="disposing">是否释放托管资源</param>
    protected virtual void Dispose(Boolean disposing)
    {
        if (disposing)
        {
            Payload.TryDispose();
            Payload = null;
        }
    }
    #endregion

    #region 方法
    /// <summary>根据请求创建配对的响应消息</summary>
    /// <returns>响应消息实例</returns>
    public virtual IMessage CreateReply()
    {
        if (Reply) throw new InvalidOperationException("Cannot create response message based on response message");

        var msg = CreateInstance();
        msg.Reply = true;

        return msg;
    }

    /// <summary>创建当前类型的新实例</summary>
    /// <remarks>子类可重写以避免反射开销,或实现对象池化复用</remarks>
    /// <returns>新的消息实例</returns>
    protected virtual Message CreateInstance()
    {
        var type = GetType();
        if (type == typeof(Message)) return new Message();

        if (type.CreateInstance() is Message msg) return msg;

        throw new InvalidOperationException($"Cannot create an instance of type [{type.FullName}]");
    }

    /// <summary>从数据包中读取消息</summary>
    /// <param name="pk">原始数据包</param>
    /// <returns>是否成功解析</returns>
    public virtual Boolean Read(IPacket pk)
    {
        Payload = pk;

        return true;
    }

    /// <summary>把消息转为封包</summary>
    /// <returns>序列化后的数据包</returns>
    public virtual IPacket? ToPacket() => Payload;

    /// <summary>重置消息状态,用于对象池复用</summary>
    /// <remarks>子类应重写此方法以重置所有字段到初始状态</remarks>
    public virtual void Reset()
    {
        Reply = false;
        Error = false;
        OneWay = false;
        Payload = null;
    }
    #endregion
}