zoukankan      html  css  js  c++  java
  • C#泛型设计的一个小陷阱.

    距离上次发表博客已经有几年了. 对于没能坚持更新博客,实在是感觉到甚是惭愧. 

    闲言少叙, 直接切入主题.

    背景

    最近一直在对于公司一个网络通信服务程序使用.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. 这样问题就都解决了.

  • 相关阅读:
    ros 使用命令测试topic
    python unicode
    python ros 回充demo
    python ros 回充调用demo
    flask报错No module named 'flask.ext'
    python flask 接口
    ros 安装c++编译的可执行文件
    Linux-Ubuntu14.04下mongodb安装部署
    如何在Ubuntu 14.04中安装最新版Eclipse
    ubuntu 14.04 安装redis5.0.3
  • 原文地址:https://www.cnblogs.com/james2010/p/10483645.html
Copyright © 2011-2022 走看看