为什么这个静态变量在使用泛型时不增加?
本文关键字:泛型 增加 静态 变量 为什么 | 更新日期: 2023-09-27 18:14:50
我需要一个特定的类来包含一个静态成员,该成员跟踪该类实例的每次实例化,本质上是为了使该类的每个实例都有一个唯一的索引。它适用于非泛型类,但当实例之间的类型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 23
1一旦类型T切换为int而不是string,计数器就会重置。
这是设计失败的吗?如果是,原因是什么?我该如何解决?还是一个bug?这在某种程度上是有意义的,因为类型T是泛型的,在类声明中,但是。
每个不同的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);
}
}
不是bug——这是设计的结果,是泛型工作方式的结果。
像A<T>
这样的泛型作为模板-当你使用类型参数时,编译器会生成一个实际的T
类型的类,并且会为每个不同类型的T
创建一个不同的类。
这解释了您看到的结果——A<int>
有一个静态字段,A<string>
有另一个静态字段。
这是因为具有不同泛型类型参数的类在底层生成了不同的类型。正如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
}
}
泛型类是创建其他类的模板。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++;
}
}
具有不同类型参数的泛型是不同的类型。所以
A<int>
和A<string>
是不同的类,所以分配了不同的静态量
这是设计。A<int>
的实例不是A<string>
的实例,它们是不同的类,所以每个类有两个静态变量。
A<int>
实际上与A<string>
是一个不同的类,因此它们有不同的静态计数器
这就是Resharper在泛型中标记静态变量的原因,因为似乎很少有程序员理解静态变量,尤其是泛型中的静态变量