SoftNumerical.cs 9.77 KB
using HslCommunication.Core;
using System;
using System.Text;
using System.Threading;

namespace HslCommunication.BasicFramework
{
    /********************************************************************************************
     * 
     *    一个高度灵活的流水号生成的类,允许根据指定规则加上时间数据进行生成
     * 
     *    根据保存机制进行优化,必须做到好并发量
     * 
     ********************************************************************************************/




    /// <summary>
    /// 一个用于自动流水号生成的类,必须指定保存的文件,实时保存来确认安全
    /// </summary>
    /// <remarks>
    /// <note type="important">
    /// 序号生成器软件,当获取序列号,清空序列号操作后,会自动的将ID号存储到本地的文件中,存储方式采用乐观并发模型实现。
    /// </note>
    /// </remarks>
    /// <example>
    /// 此处举个例子,也是Demo程序的源代码,包含了2个按钮的示例和瞬间调用100万次的性能示例。
    /// <note type="tip">百万次调用的实际耗时取决于计算机的性能,不同的计算机的表现存在差异,比如作者的:i5-4590cpu,内存ddr3-8G表示差不多在800毫秒左右</note>
    /// <code lang="cs" source="TestProject\HslCommunicationDemo\FormSeqCreate.cs" region="FormSeqCreate" title="示例代码" />
    /// </example>
    public sealed class SoftNumericalOrder : SoftFileSaveBase
    {
        #region Constructor

        /// <summary>
        /// 实例化一个流水号生成的对象
        /// </summary>
        /// <param name="textHead">流水号的头文本</param>
        /// <param name="timeFormate">流水号带的时间信息</param>
        /// <param name="numberLength">流水号数字的标准长度,不够补0</param>
        /// <param name="fileSavePath">流水号存储的文本位置</param>
        public SoftNumericalOrder(string textHead, string timeFormate, int numberLength, string fileSavePath)
        {
            LogHeaderText = "SoftNumericalOrder";
            TextHead = textHead;
            TimeFormate = timeFormate;
            NumberLength = numberLength;
            FileSavePath = fileSavePath;
            LoadByFile();

            AsyncCoordinator = new HslAsyncCoordinator(() =>
              {
                  if (!string.IsNullOrEmpty(FileSavePath))
                  {
                      using (System.IO.StreamWriter sw = new System.IO.StreamWriter(FileSavePath, false, Encoding.Default))
                      {
                          sw.Write(CurrentIndex);
                      }
                  }
              });

        }

        #endregion

        #region Private Member

        /// <summary>
        /// 当前的生成序列号
        /// </summary>
        private long CurrentIndex = 0;
        /// <summary>
        /// 流水号的文本头
        /// </summary>
        private string TextHead = string.Empty;
        /// <summary>
        /// 时间格式默认年月日
        /// </summary>
        private string TimeFormate = "yyyyMMdd";
        /// <summary>
        /// 流水号数字应该显示的长度
        /// </summary>
        private int NumberLength = 5;

        #endregion

        #region Public Method

        /// <summary>
        /// 获取流水号的值
        /// </summary>
        /// <returns>字符串信息</returns>
        public override string ToSaveString()
        {
            return CurrentIndex.ToString();
        }

        /// <summary>
        /// 加载流水号
        /// </summary>
        /// <param name="content">源字符串信息</param>
        public override void LoadByString(string content)
        {
            CurrentIndex = Convert.ToInt64(content);
        }

        /// <summary>
        /// 清除流水号计数,进行重新计数
        /// </summary>
        public void ClearNumericalOrder()
        {
            Interlocked.Exchange(ref CurrentIndex, 0);
            AsyncCoordinator.StartOperaterInfomation();
        }

        /// <summary>
        /// 获取流水号数据
        /// </summary>
        /// <returns>新增计数后的信息</returns>
        public string GetNumericalOrder()
        {
            long number = Interlocked.Increment(ref CurrentIndex);
            AsyncCoordinator.StartOperaterInfomation();
            if (string.IsNullOrEmpty(TimeFormate))
            {
                return TextHead + number.ToString().PadLeft(NumberLength, '0');
            }
            else
            {
                return TextHead + DateTime.Now.ToString(TimeFormate) + number.ToString().PadLeft(NumberLength, '0');
            }
        }

        /// <summary>
        /// 获取流水号数据
        /// </summary>
        /// <param name="textHead">指定一个新的文本头</param>
        /// <returns>带头信息的计数后的信息</returns>
        public string GetNumericalOrder(string textHead)
        {
            long number = Interlocked.Increment(ref CurrentIndex);
            AsyncCoordinator.StartOperaterInfomation();
            if (string.IsNullOrEmpty(TimeFormate))
            {
                return textHead + number.ToString().PadLeft(NumberLength, '0');
            }
            else
            {
                return textHead + DateTime.Now.ToString(TimeFormate) + number.ToString().PadLeft(NumberLength, '0');
            }
        }

        /// <summary>
        /// 单纯的获取数字形式的流水号
        /// </summary>
        /// <returns>新增计数后的信息</returns>
        public long GetLongOrder()
        {
            long number = Interlocked.Increment(ref CurrentIndex);
            AsyncCoordinator.StartOperaterInfomation();
            return number;
        }

        #endregion

        #region High Performance Save

        /// <summary>
        /// 高性能存储块
        /// </summary>
        private HslAsyncCoordinator AsyncCoordinator = null;



        #endregion
    }


    /// <summary>
    /// 一个简单的不持久化的序号自增类,采用线程安全实现,并允许指定最大数字,将包含该最大值,到达后清空从指定数开始
    /// </summary>
    public sealed class SoftIncrementCount : IDisposable
    {
        #region Constructor

        /// <summary>
        /// 实例化一个自增信息的对象,包括最大值
        /// </summary>
        /// <param name="max">数据的最大值,必须指定</param>
        /// <param name="start">数据的起始值,默认为0</param>
        public SoftIncrementCount(long max, long start = 0)
        {
            this.start = start;
            this.max = max;
            current = start;
            hybirdLock = new SimpleHybirdLock();
        }

        #endregion

        #region Private Member

        private long start = 0;
        private long current = 0;
        private long max = long.MaxValue;
        private SimpleHybirdLock hybirdLock;

        #endregion

        #region Public Method

        /// <summary>
        /// 获取自增信息
        /// </summary>
        /// <returns>计数自增后的值</returns>
        public long GetCurrentValue()
        {
            long value = 0;
            hybirdLock.Enter();

            value = current;
            current += IncreaseTick;
            if (current > max)
            {
                current = start;
            }

            hybirdLock.Leave();
            return value;
        }

        /// <summary>
        /// 重置当前序号的最大值
        /// </summary>
        /// <param name="max">最大值</param>
        public void ResetMaxNumber(long max)
        {
            hybirdLock.Enter();

            if (max > start)
            {
                if (max < current)
                    current = start;
                this.max = max;
            }

            hybirdLock.Leave();
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// 增加的单元,如果设置为0,就是不增加。注意,不能小于0
        /// </summary>
        public int IncreaseTick { get; set; } = 1;

        #endregion

        #region Object Override

        /// <summary>
        /// 返回表示当前对象的字符串
        /// </summary>
        /// <returns>返回具体的值信息</returns>
        public override string ToString()
        {
            return $"SoftIncrementCount[{this.current}]";
        }

        #endregion

        #region IDisposable Support

        private bool disposedValue = false; // 要检测冗余调用

        void Dispose(bool disposing)
        {
            if (!disposedValue)
            {
                if (disposing)
                {
                    // TODO: 释放托管状态(托管对象)。

                    hybirdLock.Dispose();
                }

                // TODO: 释放未托管的资源(未托管的对象)并在以下内容中替代终结器。
                // TODO: 将大型字段设置为 null。


                disposedValue = true;
            }
        }

        // TODO: 仅当以上 Dispose(bool disposing) 拥有用于释放未托管资源的代码时才替代终结器。
        // ~SoftIncrementCount() {
        //   // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
        //   Dispose(false);
        // }

        // 添加此代码以正确实现可处置模式。
        /// <summary>
        /// 释放当前对象所占用的资源
        /// </summary>
        public void Dispose()
        {
            // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
            Dispose(true);
            // TODO: 如果在以上内容中替代了终结器,则取消注释以下行。
            // GC.SuppressFinalize(this);
        }

        #endregion
    }
}