我需要一个特定的类来包含一个静态成员,该成员每次实例化该类的一个实例时都会跟踪它,这实际上是为了使每个类的实例都有一个唯一的索引。它适用于非泛型类,但只要类型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是通用的,在类声明中,但是......
答案 0 :(得分:31)
每个不同的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);
}
}
答案 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在泛型中标记静态变量的原因,因为很少有程序员能够理解静态算法,尤其是泛型中的静态变量