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

时间:2011-11-15 22:34:01

标签: c# .net 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>(); 
    }
}

输出结果为:

1

2

3

1

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

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

7 个答案:

答案 0 :(得分:31)

每个不同的TA<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);      
   }
}

答案 1 :(得分:25)

不是错误 - 这是设计上的,是仿制药工作原理的结果。

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

这解释了您看到的结果 - A<int>有一个静态字段,A<string>有一个静态字段。

答案 2 :(得分: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
    }
}

答案 3 :(得分:7)

泛型类是创建其他类的模板。 List<String>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++;
    }
}

答案 4 :(得分:5)

具有不同类型参数的泛型是不同类型。因此A<int>A<string>是不同的类,因此分配了不同的静态。

答案 5 :(得分:3)

这是设计的。 A<int>的实例不是A<string>的实例,它们是不同的类,因此每个类有2个静态变量。

答案 6 :(得分:0)

A<int>实际上是一个与A<string>不同的类,因此它们有不同的静态计数器

这就是Resharper在泛型中标记静态变量的原因,因为很少有程序员能够理解静态算法,尤其是泛型中的静态变量