C#中的隐形坑之泛型基类中的静态变量

hp-root / 2023-04-28 / 原文

切记:泛型基类中定义的静态变量,在各子类中是不会共享数据的。

一般在进程内共享数据可选择定义全局const变量或static变量。本文的主角就是static变量。例如我们要定义一个可以跨方法使用的事务时,会想到在基类中定义一个静态变量:

[ThreadStatic]
public static IDbTransaction _tran;

  

然后在各子类中使用该共享的变量开启事务操作。本文的问题就出在了这里,基类使用了泛型,并在其中定义了静态变量,可各子类中却无法共享这个静态变量的值,而是独立拥有自己的值。

下面将通过一个测试例子来说明这点。先定义一个泛型基类,并声明一个静态变量。

protected BaseClass<T> where T:class,new()
{
     static int Num=0;
}

然后定义两个子类继承基类

public class A:BaseClass<D>
{
     public A()
    {
            Console.Write(Num.ToString());
            Num++;
     }
}

  

public class B:BaseClass<D>
{
     public B()
     {
           Console.Write(Num.ToString());
           Num++;
     }
}

  

public class D
{
}

  

static void Main()
{
        A a=new A();
        //控制台会输出0

        B b=new B();
         //控制台输出的还是0
}

发现两次输出的都是0,明明在A的构造函数里更改Num的值了。由此可见,子类中的Num是独立的,不会共享数据。

解决办法是将静态变量的声明放到泛型基类外面,例如:

public class AA
{
    public static int Num=0;
}

  

然后在泛型基类中可以改变AA.Num的值,改变之后,各子类中访问的都是最新的。
public class A:BaseClass<D>
{
     public A()
     {
            Console.Write(AA.Num.ToString());
            AA.Num++;
     }
}

public class B:BaseClass<D>
{
     public B()
     {
           Console.Write(AA.Num.ToString());
           AA.Num++;
     }
}

static void Main()
{
        A a=new A();
        //控制台输出0

        B b=new B();
         //控制台输出1
}