记录一个C#静态变量的问题

本来想写一个日志类,初始化是获取streamwriter,然后记录日志时write,flush,这样可以避免重复打开文件,可是streamwriter莫名其妙变成null了,于是写了一个简单的测试demo

using System;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Text;

namespace ConsoleApp1
{
    class Tmp
    {
        public Tmp()
        {
            System.Console.WriteLine("tmp construct");
        }

        ~Tmp()
        {
            System.Console.WriteLine("~tmp");
        }
    }

    class Handle
    {
        private static Handle h = new Handle();
        private static Tmp t = null;
        private static int a = getA();

        public Handle()
        {
            System.Console.WriteLine("Handle construct");
            t = new Tmp();
        }

        public static Tmp getTmp()
        {
            return t;
        }

        public static int getA()
        {
            System.Console.WriteLine("getA");
            return 1;
        }
        
        ~Handle()
        {
            System.Console.WriteLine("~Handle");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            System.Console.WriteLine("Main");
            if (null == Handle.getTmp())
            {
                System.Console.WriteLine("t is null");
            }
            else
            {
                System.Console.WriteLine("t not null");
            }

            System.Console.Read();
        }
    }
}

输出如下

Main
Handle construct
tmp construct
getA
t is null

System.Console.Read();生效前Tmp的构造函数发生了,但是没有经过析构函数就莫名其妙变成null,

Handle的构造函数发生在Main输出之后,此输出是Handle的静态变量h初始化时发生的,因为初始化是赋值为new Handle();

Tmp构造函数是在Handle的构造函数中调用的,唯一赋值null的地方在初始化时,

于是得出以下结论:

1.静态变量不是立即初始化,而是在第一次调用时初始化,因为Main输出在Handle construct之前,

2.静态变量按顺序初始化,如上打印,Handle construct在getA之前

3.静态变量一次初始化所有,如上并没有使用Handle的静态变量a,但是经过了a的初始化getA()

从以上三个结论可以再次推导出t为什么是null,

Handle的静态变量初始化时,Handle中将t也初始化了,

而第二个变量也就是t作为第二变量初始化为null,便与Handle构造函数中的赋值冲突,将t又重置为null了

也就是说,变量还是一开始都在的,只是都是空的,并没有初始化。这种情况下只需要把有使用其他变量的初始化函数放到最后面即可,或者干脆全部赋值为null,0;然后在需要初始化的地方初始化

        private static Tmp t = null;
        private static int a = getA();
        private static Handle h = new Handle();
        //private static Handle h = null;

换个顺序,t先被赋值为null,new Handle()发生时,Handle的构造函数中初始化时t被第二次赋值

于是输出:

Main
getA
Handle construct
tmp construct
t not null

最好变量定义时全部赋值为空,null,0,然后统一再次赋值或修改,这样就不会发生这种问题了,不过发生这种问题,然后把问题找出来也是个乐趣。

发布了275 篇原创文章 · 获赞 46 · 访问量 28万+

猜你喜欢

转载自blog.csdn.net/youyudexiaowangzi/article/details/96968422