C#泛型设计需要注意的一个小陷阱
前言
距离上次发表博客已经有几年了. 对于没能坚持更新博客,实在是感觉到甚是惭愧.
闲言少叙, 直接切入主题.
什么是泛型
我们在编写程序时,经常遇到两个模块的功能非常相似,只是一个是处理int数据,另一个是处理string数据,或者其他自定义的数据类型,但我们没有办法,只能分别写多个方法处理每个数据类型,因为方法的参数类型不同。有没有一种办法,在方法中传入通用的数据类型,这样不就可以合并代码了吗?泛型的出现就是专门解决这个问题的。
但泛型就简单吗?当然不是,继续往下看..
背景
最近一直在对于公司一个网络通信服务程序使用.net core 进行重构.重构的目的有两个:一是让程序能够跨平台运行. 二是优化程序代码结构是程序的可维护性有所提升. 重构的过程主要由我来设计底层的架构. 在这个过程中,由于我对C# 泛型的理解还不够深入,所以在这个方面我就犯了个错误. 希望本文能把我犯的这个错误阐述清楚, 如果能帮助园里其他朋友避免这个问题当然是最好的了.
早前的设计
先用一张图来描述早前的代码结构
Singleton<T>
:是一个单例的基类, 用来实现单例模式.
Base<T>
: 则是一个基础类,它有一些静态的属性和方法(例如访问Redis,kafka,数据库等). 这些属性和方法提供给 Child1 和 Child2 去使用.
Child1 和Child2: 相当于不同模块的业务逻辑实现.
我期望的结果是Base<T>
里面的静态成员在整个程序运行期间只有一份.
代码的实现
Singleton
public abstract class Singleton<T> where T : new() { /// <summary> /// 锁定对象 /// </summary> private static readonly object locker = new object(); /// <summary> /// T 的实例 /// </summary> static T instance = default(T); /// <summary> /// T 的实例 /// </summary> public static T Instance { get { if (null == instance) { lock (locker) { if (null == instance) { instance = new T(); } } } return instance; } } }
Base
public class Base<T> : Singleton<T> where T : new() { protected static object Object { set; get; } static Base() { Object = new object(); } }
Child1 和Child2
public class Child1 : Base<Child1> { } public class Child2 : Base<Child2> { }
我以为 Base的静态构造函数只会执行一次. 可是当我在程序里使用 Child1.Instance
和 Child2.Instance
时发现, Base的静态构造函数被执行了2次. 那么Child1.Instance
的Object和Child2.Instance
的Object对象一定不是同一个.
那么问题出现在什么地方了呢? 答案其实挺简单的:系统认为 Base<Child1>
和 Base<Child2>
并不相同. 相当于在系统里定义了Base_Child1 和Base_Child2两个类. 如果我们这么理解这个问题 ,那么Base的静态构造函数被执行了2次就不难理解了.(我觉得我已经把这个问题的成因描述清楚了,如果您没理解,欢迎在下面评论.)
如果要达到我设计的目标应该怎么做呢?
修正的设计
还是先上类图.
Base:
public class Base { protected static object Object { set; get; } static Base() { Object = new object(); } }
Singleton:
public abstract class Singleton<T>: Base where T : new() { /// <summary> /// 锁定对象 /// </summary> private static readonly object locker = new object(); /// <summary> /// T 的实例 /// </summary> static T instance = default(T); /// <summary> /// T 的实例 /// </summary> public static T Instance { get { if (null == instance) { lock (locker) { if (null == instance) { instance = new T(); } } } return instance; } } }
Child1 和Child2:
public class Child1 : Singleton<Child1> { } public class Child2 : Singleton<Child2> { }
由Singleton 来继承Base.然后Child1 和Child2来继承Singleton. 这样问题就都解决了.
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对我们的支持。
上一篇:Unity实现图片轮播组件
栏 目:C#教程
本文标题:C#泛型设计需要注意的一个小陷阱
本文地址:https://www.xiuzhanwang.com/a1/C_jiaocheng/4834.html
您可能感兴趣的文章
- 01-10深入浅出23种设计模式
- 01-10同步调用和异步调用WebService
- 01-10C#操作 JSON方法汇总
- 01-10C#影院售票系统毕业设计(2)
- 01-10C#影院售票系统毕业设计(3)
- 01-10C#影院售票系统毕业设计(1)
- 01-10C#影院售票系统毕业设计(4)
- 01-10C#实现流程图设计器
- 01-10详解C#中的泛型以及编程中使用泛型的优点
- 01-10Python设计模式编程中的备忘录模式与对象池模式示例
阅读排行
本栏相关
- 01-10C#通过反射获取当前工程中所有窗体并
- 01-10关于ASP网页无法打开的解决方案
- 01-10WinForm限制窗体不能移到屏幕外的方法
- 01-10WinForm绘制圆角的方法
- 01-10C#实现txt定位指定行完整实例
- 01-10WinForm实现仿视频播放器左下角滚动新
- 01-10C#停止线程的方法
- 01-10C#实现清空回收站的方法
- 01-10C#通过重写Panel改变边框颜色与宽度的
- 01-10C#实现读取注册表监控当前操作系统已
随机阅读
- 08-05dedecms(织梦)副栏目数量限制代码修改
- 08-05DEDE织梦data目录下的sessions文件夹有什
- 01-10delphi制作wav文件的方法
- 01-10C#中split用法实例总结
- 04-02jquery与jsp,用jquery
- 01-10SublimeText编译C开发环境设置
- 01-11Mac OSX 打开原生自带读写NTFS功能(图文
- 08-05织梦dedecms什么时候用栏目交叉功能?
- 01-10使用C语言求解扑克牌的顺子及n个骰子
- 01-11ajax实现页面的局部加载