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 
        
  • 相关阅读:
    js中的原生Ajax和JQuery中的Ajax
    this的用法
    static的特性
    时政20180807
    java compiler没有1.8怎么办
    Description Resource Path Location Type Java compiler level does not match the version of the installed Java project facet Unknown Faceted Project Problem (Java Version Mismatch)
    分词器
    [数算]有一个工程甲、乙、丙单独做,分别要48天、72天、96天完成
    一点感想
    解析Excel文件 Apache POI框架使用
  • 原文地址:https://www.cnblogs.com/wuhuacong/p/2418786.html
Copyright © 2011-2022 走看看