使用泛型时,为什么这个静态变量不会递增?

Sea*_*man 28 .net c# generics static auto-increment

我需要一个特定的类来包含一个静态成员,该成员每次实例化该类的一个实例时都会跟踪,实质上是这样每个类的实例都有一个唯一的索引.它适用于非泛型类,但只要类型T在实例之间不同,这种通用实现就会失败:

class A<T>
{
   private static int counter;

   private static int Counter {
       get { 
          Increment(); 
          return counter; 
       }
   }

   private static void Increment() {
       counter++; 
   }

   public int Index; 

   public A()
   {
       this.Index = Counter; // using A<T>.Counter makes no difference

       Console.WriteLine(this.Index);      
   }
}


class Program
{
    static void Main(string[] args)
    {
        var a = new A<string>();
        var b = new A<string>(); 
        var c = new A<string>();
        var d = new A<int>(); 
    }
}
Run Code Online (Sandbox Code Playgroud)

输出是:

1

2

3

1

只要类型T切换到int而不是字符串,计数器就会重置.

这是否因设计失败,如果是这样,原因是什么或如何绕过它?或者这是一个错误?它在某种程度上是有道理的,因为类型T是通用的,在类声明中,但是......

Eni*_*ity 32

每个不同的T创建一个新类A<T>,因此不同的静态计数器.

要解决这个问题,您可以使用继承,如下所示:

abstract class A
{
   protected static int counter;
}

class A<T> : A
{
   private static int Counter {
       get { 
          Increment(); 
          return counter; 
       }
   }

   private static void Increment() {
       counter++; 
   }

   public int Index; 

   public A()
   {
       this.Index = Counter;

       Console.WriteLine(this.Index);      
   }
}
Run Code Online (Sandbox Code Playgroud)


Ode*_*ded 26

这不是一个错误 - 这是设计的,是泛型工作方式的结果.

像您A<T>一样的泛型类型作为模板 - 当您使用类型参数时,编译器会生成具有该类型的实际类(此类将被重用,但将为每个不同类型创建不同的类).

这解释了你看到的结果 - 有一个静态字段T和一个静态字段T.


sll*_*sll 10

这是因为在引擎盖下为具有不同泛型类型参数的类生成了不同的类型.这种差异仅适用于Ben在评论中所注意到的值类型参数.

看看这些MSDN文章:

编辑:

考虑以下代码:

public abstract class GenericBase<T>
{
    public static int Counter { get; set; }        
}

public class GenericInt : GenericBase<int>
{        
}

public class GenericLong : GenericBase<long>
{        
}

public class GenericDecimal : GenericBase<decimal>
{        
}

[TestFixture]
public class GenericsTests
{
    [Test]
    public void StaticContextValueTypeTest()
    {
        GenericDecimal.Counter = 10;
        GenericInt.Counter = 1;
        GenericLong.Counter = 100;

       // !! At this point value of the Counter property
       // in all three types will be different - so does not shared across
       // all types
    }
}
Run Code Online (Sandbox Code Playgroud)

  • "产生不同类型"有点误导.为每组泛型类型参数实例化静态成员变量.方法仅针对值类型实例化,所有引用类型共享单个实现. (5认同)

Han*_*ood 7

泛型类是创建其他类的模板.A List<String>和a List<int>是两个完全不同的类,尽管它们都来源于List<T>.

让您的泛型类引用一个包含计数器的非泛型类.不要将静态类放在泛型类中.这将导致为每个值生成静态类T.

class A<T>
{
    private static int Counter {
        get {
            ACounter.Increment();
            return ACounter.counter;
        }
    }

    public int Index;

    public A()
    {
       this.Index = Counter;

       Console.WriteLine(this.Index);
    }
}

static class ACounter
{
    static ACounter() {
        counter = 0;
    }

    public static int counter {get; private set;};

    public static void Increment() {
        counter++;
    }
}
Run Code Online (Sandbox Code Playgroud)


drd*_*cox 5

具有不同类型参数的泛型是不同类型.所以A<int>并且A<string>是不同的类,因此分配不同的静态.