十字星

  • 首页
  • 技术
  • 随笔
  • 瞎折腾
  • 平面设计
  • 文集
  • 留言
  • 其他
    • API测试
  1. 首页
  2. 技术
  3. 正文

C# 单例模式基类如何初始化子类

2021-05-20 1275点热度 1人点赞 0条评论

项目需要,有很多操作需要在线程中执行,而且启动线程的结构完全相同,因此想到用父子类并重写基类方法的方式实现,于是啪啪啪就写了

不正确-父类

using System;
using System.Threading;

namespace HuluChajian.ThreadHelper
{
    internal class ThreadHelper
    {
        static ThreadHelper _instance;
        public static ThreadHelper Instance
        {
            get
            {
                return _instance == null ? _instance = new ThreadHelper() : _instance;
            }
        }

        /// <summary>标识线程是否已经启动,已经启动值为true</summary>
        bool isStart = false;

        /// <summary>启动线程[一般情况下不重写此方法]</summary>
        public virtual void Start()
        {
            if (isStart) { return; }//已经启动过不能再次启动,直接返回.
            isStart = true;

            new Thread(() =>
            {
                while (isStart)
                {
                    Internal_Start();
                }
            }).Start();
        }

        /// <summary>启动线程需要调用的自定义方法</summary>
        protected virtual void Internal_Start()
        {
            Console.WriteLine("ThreadHelper");

            Thread.Sleep(1000);//每隔1秒执行一次 
        }

        /// <summary>停止线程</summary>
        public void Stop()
        {
            isStart = false;
            Internal_Stop();
        }

        /// <summary>停止线程需要调用的自定义方法</summary>
        protected virtual void Internal_Stop()
        {
            Console.WriteLine("ThreadHelper---Stop");
        }
    }
}

不正确-子类

using System;
using System.Threading;

namespace HuluChajian.ThreadHelper
{
    /// <summary>
    /// 守护进程的保活线程,保持update.exe意外关闭后能自动重启
    /// </summary>
    internal class ThreadProtectProcess : ThreadHelper
    {
        protected override void Internal_Start()
        {
            Console.WriteLine("ThreadProtectProcess");

            Thread.Sleep(1000);//每隔1秒执行一次 
        }
        protected override void Internal_Stop()
        {
            Console.WriteLine("ThreadProtectProcess---Stop");
        }
    }
}

调用测试

using HuluChajian.ThreadHelper;
using System;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            ThreadProtectProcess.Instance.Start();
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            ThreadProtectProcess.Instance.Stop();
        }
    }
}

写完随便新建一个空窗体测试下,才发现这种写法完全不行,单例在父类中初始化的是父类自己,无论用哪个子类调用,永远执行不到子类重写的方法.

首先想到的是将return _instance == null ? _instance = new ThreadHelper() : _instance;代码中的new ThreadHelper()改为虚方法,在子类中重写,一测试发现这个是静态属性中内容,方法也必须是静态方法,而静态成员不能标记为override、virtual、abstract。问了同事们,也没有哪个知道,后来还是在博客园找到一篇文章才解决这个单例实例化问题,就是使用反射实例化成子类,代码如下

正确-父类-使用泛型、反射

using System;
using System.Threading;

namespace HuluChajian.ThreadHelper
{
    internal class ThreadHelper<T> where T : class
    {
        static T _instance;
        public static T Instance
        {
            get
            {
                return _instance == null ? _instance = (T)System.Reflection.Assembly.GetAssembly(typeof(T)).CreateInstance(typeof(T).ToString()) : _instance;
            }
        }

        /// <summary>标识线程是否已经启动,已经启动值为true</summary>
        bool isStart = false;

        /// <summary>启动线程[一般情况下不重写此方法]</summary>
        public virtual void Start()
        {
            if (isStart) { return; }//已经启动过不能再次启动,直接返回.
            isStart = true;

            new Thread(() =>
            {
                while (isStart)
                {
                    Internal_Start();
                }
            }).Start();
        }

        /// <summary>启动线程需要调用的自定义方法</summary>
        protected virtual void Internal_Start()
        {
            Console.WriteLine("ThreadHelper");

            Thread.Sleep(1000);//每隔1秒执行一次 
        }

        /// <summary>停止线程</summary>
        public void Stop()
        {
            isStart = false;
            Internal_Stop();
        }

        /// <summary>停止线程需要调用的自定义方法</summary>
        protected virtual void Internal_Stop()
        {
            Console.WriteLine("ThreadHelper---Stop");
        }
    }
}

正确-子类

using System;
using System.Threading;

namespace HuluChajian.ThreadHelper
{
    /// <summary>
    /// 守护进程的保活线程,保持update.exe意外关闭后能自动重启
    /// </summary>
    internal class ThreadProtectProcess : ThreadHelper<ThreadProtectProcess>
    {
        protected override void Internal_Start()
        {
            Console.WriteLine("ThreadProtectProcess");

            Thread.Sleep(1000);//每隔1秒执行一次 
        }
        protected override void Internal_Stop()
        {
            Console.WriteLine("ThreadProtectProcess---Stop");
        }
    }
}

此时在测试调用ThreadProtectProcess.Instance.Start();后,会每隔1秒在vs输出窗口显示 ThreadProtectProcess 字符串,调用ThreadProtectProcess.Instance.Stop();后输出 ThreadProtectProcess---Stop字符串并且不再输出 ThreadProtectProcess字符串,线程结束

 

参考链接c# 单例模式基类(基于反射初始化子类) - by-lhc - 博客园 (cnblogs.com)

本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可
标签: C# WinForm
最后更新:2021-05-20

cxw

技术宅,最喜瞎折腾.

点赞
< 上一篇
下一篇 >
最新 热点 随机
最新 热点 随机
git迁移项目中的某个目录到新项目 winform判断设计模式还是运行时模式 C# 中的where T : class, new() 到底是什么意思? 解决安装.NET失败并提示“无法建立到信任根颁发机构的证书链” 关闭.net4.0的http访问默认代理 删除名称最后带空格的文件夹
[转]安装中文VS2008 SP1和。NET3.5SP1后智能提示是英文的解决办法 管理员收不到普通权限的SendMessage消息 记录备忘:WMsg参数常量值 Oracle 数据库clob字段空值判断 C# 获取json中的某一属性值 C#程序退出托盘图标NotifyIcon不会自动消失的解决方法
标签聚合
WordPress Linux CentOS IT PHP W10 WinForm Excel 工具 C#
最近评论
admin 发布于 4 年前(01月22日) 使用Andi Dittrich作者的插件Enlighter实现
alex 发布于 4 年前(01月22日) 博主,请问把代码贴到博客里可以复制是怎么实现的

COPYRIGHT © 2021 十字星. ALL RIGHTS RESERVED

Theme Kratos Made By Seaton Jiang