zoukankan      html  css  js  c++  java
  • 厚积薄发,丰富的公用类库积累,助你高效进行系统开发(11)各种线程相关操作类

    俗话说,一个好汉十个帮,众人拾柴火焰高等都说明一个道理,有更多的资源,更丰富的积累,都是助你走向成功,走向顶峰的推动力。

    本篇的公用类库的介绍主题是程序开发中多线程操作环境中,常用到的线程相关类,本篇随笔介绍包含单件创建辅助类、Timer定时器、委托处理辅助类、队列的线程处理服务辅助类、可以取消执行操作的线程池辅助类、线程池辅助类、线程辅助类等对象,这些辅助类覆盖了多线程开发中绝大多数的应用。良好的封装及操作,给我们提供非常方便、高效的线程操作处理。

    本篇继续继续整理优化已有的共用类库,并继续发表随笔介绍公用类库的接口方法以及详细使用操作,力求给自己继续优化,积攒更丰富的公用类库资源,加深了解的同时,也给大家展现公用类库好的方面。

    厚积薄发,丰富的公用类库积累,助你高效进行系统开发(10)---各种线程同步的集合类
    厚积薄发,丰富的公用类库积累,助你高效进行系统开发(9)----各种常用辅助类
    厚积薄发,丰富的公用类库积累,助你高效进行系统开发(8)----非对称加密、BASE64加密、MD5等常用加密处理
    厚积薄发,丰富的公用类库积累,助你高效进行系统开发(7)-----声音播放、硬件信息、键盘模拟及钩子、鼠标模拟及钩子等设备相关 
    厚积薄发,丰富的公用类库积累,助你高效进行系统开发(6)----全屏截图、图标获取、图片打印、页面预览截屏、图片复杂操作等
    厚积薄发,丰富的公用类库积累,助你高效进行系统开发(5)----热键、多线程、窗体动画冻结等窗体操作
    厚积薄发,丰富的公用类库积累,助你高效进行系统开发(4)----CSV、Excel、INI文件、独立存储等文件相关
    厚积薄发,丰富的公用类库积累,助你高效进行系统开发(3)----数据库相关操作
    厚积薄发,丰富的公用类库积累,助你高效进行系统开发(2)----常用操作
    厚积薄发,丰富的公用类库积累,助你高效进行系统开发(1)----开篇总结

    1、单件操作辅助类 Singleton。  

    实现效果

    1) 本辅助类主要是用来方便实现类对象的单件实例操作,减少重复写单件实现代码的繁琐,简化类的代码。 

    2)创建一个类对象的单件实例,类对象的构造函数不能为Public修饰符的,一般为private。

    实现代码

    1)辅助类提供的方法源码如下所示: 

    /// <summary>    
    /// 创建一个类对象的单件实例,类对象的构造函数不能为Public修饰符的,一般为private。
    /// </summary>
    /// <typeparam name="T">待创建的对象类</typeparam>
    public static class Singleton<T> where T : class
    {
    static volatile T _instance;
    static object _lock = new object();

    static Singleton()
    {
    }

    /// <summary>
    /// 创建/获取一个可以new的类对象的单件实例
    /// </summary>
    public static T Instance
    {
    get
    {
    if (_instance == null)
    lock (_lock)
    {
    if (_instance == null)
    {
    ConstructorInfo constructor = null;

    try
    {
    // 构造函数不包含public修饰符的
    constructor = typeof(T).GetConstructor(BindingFlags.Instance |
    BindingFlags.NonPublic, null, new Type[0], null);
    }
    catch (Exception exception)
    {
    throw new InvalidOperationException(exception.Message, exception);
    }

    if (constructor == null || constructor.IsAssembly)
    {
    throw new InvalidOperationException(string.Format("在'{0}'里面没有找到private或者protected的构造函数。", typeof(T).Name));
    }

    _instance = (T)constructor.Invoke(null);
    }
    }

    return _instance;
    }
    }

    2)辅助类Singleton的使用例子代码如下所示

    /// <summary>    
    /// 单件测试类
    /// </summary>
    public class TestSingletonClass
    {
    /// <summary>
    /// 私有构造函数
    /// </summary>
    private TestSingletonClass()
    {
    }

    public void ShowMessage()
    {
    MessageUtil.ShowTips("单件实例测试函数");
    }
    }

    private void btnSingleton_Click(object sender, EventArgs e)
    {
    //单件辅助类使用代码
    Singleton<TestSingletonClass>.Instance.ShowMessage();
    }


    如果没有使用单件辅助类,那么单件的测试类将会需要这样书写,很明显多了很多行代码,如果每个想单件处理的类都要这样写,代码量还是很可观的,而且比较繁琐。

    /// <summary>    
    /// 单件测试类
    /// </summary>
    public class TestSingletonClass
    {
    private static TestSingletonClass m_Instance;

    /// <summary>
    /// 单件实例
    /// </summary>
    public static TestSingletonClass Instance
    {
    get
    {
    if (m_Instance == null)
    {
    m_Instance = new TestSingletonClass();
    }
    return m_Instance;
    }
    }

    /// <summary>
    /// 私有构造函数
    /// </summary>
    private TestSingletonClass()
    {
    }

    public void ShowMessage()
    {
    MessageUtil.ShowTips("单件实例测试函数");
    }
    }

    2、定期执行某些任务的定时器辅助类Timer。  

    实现效果

    1)  本辅助类主要是用来方便实现定时器辅助类,功能和另外一个定时器辅助类TimerHelper差不多。

    2) 定时器操作,都通过对象锁以及在运行处理事件的时候,动态改变间隔事件为无限等待,处理完成后修改为间隔时间的方式,实现对定时器的正常、安全执行,不会发生运行一半又跳到下一个的处理过程中。 

    3).NET提供了3种定时器实现,他们的特点如下所示。该Timer辅助类是基于Threading.Timer的定时器实现。

    Server Timers System.Timers.Timer 基于服务器的计时器,位于"工具箱"的“组件”选项卡上
    Thread Timers System.Threading.Timer 在编程时使用的线程计时器
    Windows Timers System.Windows.Forms.Timer 基于 Windows 的标准计时器,"工具箱"的"Windows 窗体"选项卡上;

    实现代码

    1)辅助类提供的方法接口如下所示: 

    #region 事件或属性    

    /// <summary>
    /// 按定时器周期定期引发的事件
    /// </summary>
    public event EventHandler Elapsed;

    /// <summary>
    /// 定时器任务间隔(毫秒)
    /// </summary>
    public int Period { get; set; }

    /// <summary>
    /// 指示是否在方法开始的时候,启动定时器Elapsed事件一次。默认为false。
    /// </summary>
    public bool RunOnStart { get; set; }

    #endregion

    #region 构造函数

    /// <summary>
    /// 创建一个定时器
    /// </summary>
    /// <param name="period">定时器间隔 (毫秒)</param>
    public Timer(int period) : this(period, false)

    /// <summary>
    /// 创建一个定时器
    /// </summary>
    /// <param name="period">定时器间隔 (毫秒)</param>
    /// <param name="runOnStart">指示是否在方法开始的时候,启动定时器Elapsed事件一次</param>
    public Timer(int period, bool runOnStart)

    #endregion

    #region 方法

    /// <summary>
    /// 启动定时器
    /// </summary>
    public void Start()

    /// <summary>
    /// 停止定时器
    /// </summary>
    public void Stop()

    /// <summary>
    /// 等待定时器停止
    /// </summary>
    public void WaitToStop()


    #endregion

    2)辅助类Timer 的使用例子代码如下所示

    private void btnTimer_Click(object sender, EventArgs e)    
    {
    WHC.OrderWater.Commons.Threading.Timer timer = new WHC.OrderWater.Commons.Threading.Timer(1000, true);
    timer.Elapsed += new EventHandler(timer_Elapsed);
    timer.Start();
    }

    void timer_Elapsed(object sender, EventArgs e)
    {
    if (!this.InvokeRequired)
    return;

    this.Invoke(new MethodInvoker(delegate()
    {
    this.btnTimer.Text = DateTime.Now.ToLongTimeString();
    }));
    }

    3、定时器辅助类TimerHelper,可指定运行间隔、延迟启动时间等操作。  

    实现效果

    1) 本辅助类主要是用来方便实现定时器辅助类,可指定运行间隔、延迟启动时间等操作。功能和另外一个定时器辅助类Timer差不多。 

    2)定时器操作,都通过对象锁以及在运行处理事件的时候,动态改变间隔事件为无限等待,处理完成后修改为间隔时间的方式,实现对定时器的正常、安全执行,不会发生运行一半又跳到下一个的处理过程中。 

    实现代码

    1)辅助类提供的方法接口如下所示: 

    /// <summary>    
    /// 定时器执行操作的函数原型
    /// </summary>
    public delegate void TimerExecution();

    /// <summary>
    /// 定时器执行时调用的操作
    /// </summary>
    public event TimerExecution Execute;

    /// <summary>
    /// 创建一个指定时间间隔的定时器,并在指定的延迟后开始启动。(默认间隔为100毫秒)
    /// </summary>
    public TimerHelper()

    /// <summary>
    /// 创建一个指定时间间隔的定时器,并在指定的延迟后开始启动。
    /// </summary>
    /// <param name="interval">定时器执行操作的间隔时间(毫秒)</param>
    /// <param name="startDelay">指定的延迟时间(毫秒)</param>
    public TimerHelper(long interval, int startDelay)

    /// <summary>
    /// 创建一个指定时间间隔的定时器
    /// </summary>
    /// <param name="interval">定时器执行操作的间隔时间(毫秒)</param>
    /// <param name="start">是否启动</param>
    public TimerHelper(long interval, bool start)

    /// <summary>
    /// 启动定时器并指定延迟时间(毫秒)
    /// </summary>
    /// <param name="delayBeforeStart">指定延迟时间(毫秒)</param>
    public void Start(int delayBeforeStart)

    /// <summary>
    /// 立即启动定时器
    /// </summary>
    public void Start()

    /// <summary>
    /// 暂停定时器
    /// 注意:运行中的线程不会被停止
    /// </summary>
    public void Pause()

    /// <summary>
    /// 停止定时器
    /// 注意:运行中的线程不会被停止
    /// </summary>
    public void Stop()

    /// <summary>
    /// 定时器的处理时间
    /// </summary>
    /// <param name="obj"></param>
    public void Tick(object obj)

    /// <summary>
    /// 定时器的状态
    /// </summary>
    public TimerState State

    /// <summary>
    /// 获取或设置定时器的运行间隔
    /// </summary>
    public long Interval

    2)辅助类TimerHelper的使用例子代码如下所示

    public FrmNewHouse()    
    {
    InitializeComponent();

    if (!this.DesignMode)
    {
    this.winGridViewPager1.OnPageChanged += new EventHandler(winGridViewPager1_OnPageChanged);
    this.winGridViewPager1.OnStartExport += new EventHandler(winGridViewPager1_OnStartExport);
    this.winGridViewPager1.OnRefresh += new EventHandler(winGridViewPager1_OnRefresh);
    this.winGridViewPager1.OnGridViewMouseDoubleClick += new EventHandler(winGridViewPager1_OnGridViewMouseDoubleClick);
    this.winGridViewPager1.ShowLineNumber = true;
    this.winGridViewPager1.PagerInfo.PageSize = 20;
    this.winGridViewPager1.BestFitColumnWith = true;
    this.winGridViewPager1.AppendedMenu = this.contextMenuStrip1;
    this.winGridViewPager1.gridView1.RowCellStyle += new DevExpress.XtraGrid.Views.Grid.RowCellStyleEventHandler(gridView1_RowCellStyle);

    //使用定时器,定时刷新窗体的数据,并提示客户更新情况
    int interval = Portal.gc.GetRefreshSecond();//获取定时间隔时间
    TimerHelper timer = new TimerHelper(interval, true);
    timer.Execute += new TimerHelper.TimerExecution(timer_Execute);
    }
    }

    //通过Invoke来实现跨线程间的调用
    void timer_Execute()
    {
    if (!this.InvokeRequired)
    return;

    this.Invoke(new MethodInvoker(delegate()
    {
    NotifyNewHouse();
    }));
    }


    4、提供一个队列的线程处理服务辅助类 QueueServer。   

    实现效果

    1)  本辅助类主要是用来方便实现提供一个队列的线程处理服务操作。QueueServer是一个先入先出(FIFO)的队列处理服务。

    实现代码

    1)辅助类提供的方法接口如下所示: 

    #region  属性方法    

    /// <summary>
    /// 是否是背景线程
    /// </summary>
    public bool IsBackground

    /// <summary>
    /// 执行队列
    /// </summary>
    public T[] Items

    /// <summary>
    /// 队列数量
    /// </summary>
    public int QueueCount

    /// <summary>
    /// 将对象加到队列结尾
    /// </summary>
    /// <param name="item"></param>
    public void EnqueueItem(T item)

    /// <summary>
    /// 清除队列
    /// </summary>
    public void ClearItems()

    #endregion

    #region 线程处理

    /// <summary>
    /// 处理单个元素
    /// </summary>
    /// <param name="item">元素项目</param>
    protected virtual void OnProcessItem(T item)

    /// <summary>
    /// 处理函数
    /// </summary>
    public event Action<T> ProcessItem;

    #endregion

    2)辅助类QueueServer的使用例子代码如下所示

     private void btnQueneServer_Click(object sender, EventArgs e)    
    {
    QueueServer<PreDataInfo> queueServer = new QueueServer<PreDataInfo>();
    queueServer.IsBackground = true;
    queueServer.ProcessItem += new Action<PreDataInfo>(queueServer_ProcessItem);

    //循环入队
    for (int i = 0; i < 100; i++)
    {
    queueServer.EnqueueItem(new PreDataInfo(i.ToString(), DateTime.Now.ToString()));
    Thread.Sleep(10);
    }
    }

    /// <summary>
    /// 处理每个出队的操作
    /// </summary>
    void queueServer_ProcessItem(PreDataInfo obj)
    {
    Console.WriteLine("{0} : {1}", obj.Key, obj.Data);
    }
    }

    public class PreDataInfo
    {
    public string Key;
    public string Data;

    public PreDataInfo()
    {
    }

    public PreDataInfo(string key, string data)
    {
    this.Key = key;
    this.Data = data;
    }
    }


    5、可以取消执行操作的线程池辅助类 AbortableThreadPool。  

    实现效果

    1) 本辅助类主要是用来方便实现可以取消执行操作的线程池操作。 

    2)AbortableThreadPool线程辅助类可以使用常用的多线程处理环境中,也可以使用在有些在运行过程中可能需要取消的线程处理环境中。

    实现代码

    1)辅助类提供的方法接口如下所示: 

    /// <summary>        
    /// 把执行操作放到队列中。当线程池的线程可用的时候,方法执行。
    /// </summary>
    /// <param name="callback">一个代表将要执行方法的WaitCallback对象</param>
    public static WorkItem QueueUserWorkItem(WaitCallback callback)

    /// <summary>
    /// 把执行操作放到队列中,并指定了一个对象,它包含将要执行方法的数据。
    /// 当线程池的线程可用的时候,方法执行。
    /// </summary>
    /// <param name="callback">一个代表将要执行方法的WaitCallback对象</param>
    /// <param name="state">一个对象,它包含将要执行方法的数据</param>
    public static WorkItem QueueUserWorkItem(WaitCallback callback, object state)

    /// <summary>
    /// 取消指定的队列中的工作项。
    /// </summary>
    /// <param name="item">线程池中取消的项目</param>
    /// <param name="allowAbort">如果设置为<see langword="true"/>则允许终止线程</param>
    /// <returns>项目队列的状态</returns>
    public static WorkItemStatus Cancel(WorkItem item, bool allowAbort)

    /// <summary>
    /// 获取指定队列中工作项的状态
    /// </summary>
    /// <param name="item">线程池中工作项</param>
    /// <returns>工作项的状态</returns>
    public static WorkItemStatus GetStatus(WorkItem item)

    /// <summary>
    /// 取消所有任务
    /// </summary>
    /// <param name="allowAbort">线程是否终止</param>
    public static void CancelAll(bool allowAbort)

    /// <summary>
    /// 类似Thread.Join,等待AbortableThreadPool执行完成
    /// </summary>
    public static void Join()

    /// <summary>
    /// 类似Thread.Join,等待AbortableThreadPool执行完成
    /// </summary>
    /// <param name="millisecondsTimeout">等待的毫秒数</param>
    /// <returns></returns>
    public static bool Join(int millisecondsTimeout)

    /// <summary>
    /// 类似Thread.Join,等待AbortableThreadPool执行完成
    /// </summary>
    /// <param name="timeout">等待的时间范围</param>
    /// <returns></returns>
    public static bool Join(TimeSpan timeout)

    /// <summary>
    /// 在队列中,还未执行处理的数量
    /// </summary>
    public static int QueueCount

    /// <summary>
    /// 在执行中的线程数量
    /// </summary>
    public static int WorkingCount

    2)辅助类AbortableThreadPool的使用例子代码如下所示

    private void btnAbortableThreadPool_Click(object sender, EventArgs e)    
    {
    Console.WriteLine(string.Format("QueueCount:{0},WorkingCount:{1}", AbortableThreadPool.QueueCount, AbortableThreadPool.WorkingCount));

    WorkItem workItem1 = AbortableThreadPool.QueueUserWorkItem(new WaitCallback(Test));
    Console.WriteLine(string.Format("QueueCount:{0},WorkingCount:{1}", AbortableThreadPool.QueueCount, AbortableThreadPool.WorkingCount));

    WorkItem workItem2 = AbortableThreadPool.QueueUserWorkItem(new WaitCallback(Test));
    WorkItem workItem3 = AbortableThreadPool.QueueUserWorkItem(new WaitCallback(Test));
    WorkItem workItem4 = AbortableThreadPool.QueueUserWorkItem(new WaitCallback(Test));
    WorkItem workItem5 = AbortableThreadPool.QueueUserWorkItem(new WaitCallback(Test));
    Console.WriteLine(string.Format("QueueCount:{0},WorkingCount:{1}", AbortableThreadPool.QueueCount, AbortableThreadPool.WorkingCount));
    Thread.Sleep(1000);

    Console.WriteLine(AbortableThreadPool.Cancel(workItem1, false));
    Console.WriteLine(string.Format("QueueCount:{0},WorkingCount:{1}", AbortableThreadPool.QueueCount, AbortableThreadPool.WorkingCount));
    Thread.Sleep(1000);

    Console.WriteLine(AbortableThreadPool.Cancel(workItem1, true));
    Console.WriteLine(string.Format("QueueCount:{0},WorkingCount:{1}", AbortableThreadPool.QueueCount, AbortableThreadPool.WorkingCount));
    Thread.Sleep(1000);

    //AbortableThreadPool.CancelAll(true);//可取消所有任务
    AbortableThreadPool.Join(); //等待所有任务退出
    Console.WriteLine(string.Format("QueueCount:{0},WorkingCount:{1}", AbortableThreadPool.QueueCount, AbortableThreadPool.WorkingCount));
    }

    static void Test(object state)
    {
    int i = 100;
    while (i-- > 0)
    {
    Console.WriteLine(i);
    Thread.Sleep(new Random((int)DateTime.Now.Ticks).Next(100));
    }
    }



    6、委托处理辅助类DelegateHelper。  

    实现效果

    1) 本辅助类主要是用来方便实现委托的处理。 

    2)使用委托处理辅助类DelegateHelper,可以快速执行或者取消一些委托方法的执行。

    实现代码

    1)辅助类提供的方法接口如下所示: 

    /// <summary>    
    /// 执行委托操作
    /// </summary>
    /// <param name="target">目标委托对象</param>
    /// <param name="args">参数</param>
    public static WorkItem InvokeDelegate(Delegate target, params object[] args)

    /// <summary>
    /// 执行委托操作
    /// </summary>
    /// <param name="target">目标委托对象</param>
    public static WorkItem InvokeDelegate(Delegate target)

    /// <summary>
    /// 中止指定的队列中委托
    /// </summary>
    /// <param name="target">目标委托对象</param>
    /// <returns>项目队列中止操作的状态</returns>
    public static WorkItemStatus AbortDelegate(WorkItem target)

    2)辅助类DelegateHelper的使用例子代码如下所示

    private void btnDelegeteHelper_Click(object sender, EventArgs e)    
    {
    //无参数的委托
    DelegateHelper.InvokeDelegate(new UpdateTextDelegate(this.UpdateText));

    //有参数的委托
    DelegateHelper.InvokeDelegate(new UpdateTextDelegate2(this.UpdateText), 100);

    }
    private delegate void UpdateTextDelegate();
    private delegate void UpdateTextDelegate2(int count);
    private void UpdateText()
    {
    for (int i = 0; i < 1000; i++)
    {
    Thread.Sleep(100);
    }
    }
    private void UpdateText(int count)
    {
    for (int i = 0; i < count; i++)
    {
    Thread.Sleep(100);
    }
    }


    7、线程池辅助操作类 ThreadPoolHelper。  

    实现效果

    1) 本辅助类主要是用来方便实现线程池辅助操作。。 

    实现代码

    1)辅助类提供的方法接口如下所示:

    /// <summary>    
    /// 方法委托
    /// </summary>
    public delegate void WaitCallbackNew();

    /// <summary>
    /// 把执行方法放到队列中。
    /// 当线程池线程变为可用的时候,方法执行。
    /// </summary>
    /// <param name="callback">委托对象</param>
    public static bool QueueUserWorkItem(WaitCallbackNew callback)

    /// <summary>
    /// 把执行方法放到队列中。
    /// 当线程池线程变为可用的时候,方法执行。
    /// </summary>
    /// <param name="proc">委托对象数组</param>
    /// <returns></returns>
    public static bool QueueUserWorkItems(params WaitCallbackNew[] proc)

    /// <summary>
    ///等待指定数组中所有元素收到信号
    /// </summary>
    public static bool WaitAll()

    /// <summary>
    ///等待指定数组中任何一个元素收到信号
    /// </summary>
    /// <returns>满足等待的对象数组索引</returns>
    public static int WaitAny()

    2)辅助类ThreadPoolHelper的使用例子代码如下所示

    private void UpdateText()    
    {
    for (int i = 0; i < 50; i++)
    {
    Thread.Sleep(100);
    }
    }

    private void btnThreadPool_Click(object sender, EventArgs e)
    {
    ThreadPoolHelper.QueueUserWorkItem(new ThreadPoolHelper.WaitCallbackNew(UpdateText));
    ThreadPoolHelper.WaitAny(); //阻塞主界面线程,到5秒循环结束后,主界面可以操作
    }


    8、线程操作辅助类ThreadHelper。 

    实现效果

    1) 本辅助类主要是用来方便实现线程的各种操作,包括设置线程名称、优先级等及把执行方法放到队列中执行等基础性的线程操作。

    实现代码

    1)辅助类提供的方法接口如下所示:

    /// <summary>    
    /// 线程名称,最长不超过10个字符!
    /// </summary>
    /// <param name="name">线程名称</param>
    public static void SetThreadName(string name)

    /// <summary>
    /// 设置线程优先级
    /// </summary>
    /// <param name="priority">线程优先级</param>
    public static void SetThreadPriority(ThreadPriority priority)

    /// <summary>
    /// 设置主线程的UI Culture
    /// </summary>
    /// <param name="cultureName"></param>
    public static void SetMainThreadUICulture(string cultureName)

    /// <summary>
    /// 把执行方法放到队列中,并指定了一个对象,它包含使用该方法的数据。
    /// 当线程池线程变为可用的时候,方法执行。
    /// </summary>
    /// <param name="callBack">工作项(WaitCallback)对象</param>
    /// <param name="threadName">线程名称,最长不超过10个字符!</param>
    /// <param name="priority">线程优先级</param>
    public static bool Queue(WaitCallback callBack, string threadName, ThreadPriority priority)

    /// <summary>
    /// 把执行方法放到队列中,并指定了一个对象,它包含使用该方法的数据。
    /// 当线程池线程变为可用的时候,方法执行。
    /// </summary>
    /// <param name="callBack">工作项(WaitCallback)对象</param>
    /// <param name="threadName">线程名称,最长不超过10个字符!</param>
    /// <param name="state">执行方法的数据</param>
    /// <param name="priority">线程优先级</param>
    public static bool Queue(WaitCallback callBack, string threadName, object state, ThreadPriority priority)

    /// <summary>
    /// 线程休眠一段毫秒时间
    /// </summary>
    /// <param name="millisecondsTimeout">一段毫秒时间</param>
    public static void Sleep(int millisecondsTimeout)

    /// <summary>
    /// 线程休眠一段时间
    /// </summary>
    /// <param name="timeOut"></param>
    public static void Sleep(TimeSpan timeOut)

    2)辅助类ThreadHelper的使用例子代码如下所示

    CHM帮助文档持续更新中,统一下载地址是: http://www.iqidi.com/download/commonshelp.rar 

    最新公用类库DLL+XML注释文件下载地址是:https://files.cnblogs.com/wuhuacong/WHC.OrderWater.Commons.rar 

    主要研究技术:代码生成工具、会员管理系统、客户关系管理软件、病人资料管理软件、Visio二次开发、酒店管理系统、仓库管理系统等共享软件开发
    专注于Winform开发框架/混合式开发框架Web开发框架Bootstrap开发框架微信门户开发框架的研究及应用
      转载请注明出处:
    撰写人:伍华聪  http://www.iqidi.com 
        
  • 相关阅读:
    (五) 子类与继承
    linux7(centos7)新系统安装后要做的事!
    CentOS7系统搭建FTP服务器
    ---Docker学习随笔---基础管理部分---
    linux系统配置本地yum源
    安装redis 6.0.6
    LNMP部署
    如何在RHEL7或CentOS 7系统下修改网卡名称(亲测有效~!)
    Mysql常用基础命令操作
    MySQL版本浅介
  • 原文地址:https://www.cnblogs.com/wuhuacong/p/2418786.html
Copyright © 2011-2022 走看看