我已经使用CRTP在C#计数器中实现了,但我不知道为什么它不会因某些类型而倒计时:
using System;
using Type1 = C<char>;
using Type2 = C<int>;
class ExistingObjectCounter<CountedType>
{
private static uint existingObjects = 0;
protected ExistingObjectCounter()
{
++existingObjects;
}
~ExistingObjectCounter()
{
Console.WriteLine("Destruction of " + this + " number " + existingObjects);
--existingObjects;
}
public static uint GetNumberOfLivingObjects
{
get
{
return existingObjects;
}
}
}
class C<T> : ExistingObjectCounter<C<T>>
{
public C()
{}
public C(C<T> m)
{}
};
class ZliczaczObiektow
{
public static void createManyCClassWithStringArgument()
{
for(int i=0; i<10;++i)
new C<String>();
}
public static void Main()
{
Type1 c1 = new Type1(), c2 = new Type1(), c3 = new Type1(c2);
var ws1 = new Type2();
Console.WriteLine("existing objects of class " + c1.GetType() + ": "
+ Type1.GetNumberOfLivingObjects);
Console.WriteLine("existing objects of class " + ws1.GetType() + ": "
+ Type2.GetNumberOfLivingObjects);
createManyCClassWithStringArgument();
{
Type1 c4 = new Type1(), c5 = new Type1();
var ws2 = new Type2();
Console.WriteLine("existing objects of class " + c4.GetType() + ": "
+ Type1.GetNumberOfLivingObjects);
Console.WriteLine("existing objects of class " + ws2.GetType() + ": "
+ Type2.GetNumberOfLivingObjects);
createManyCClassWithStringArgument();
}
System.GC.Collect();
Console.WriteLine("existing objects of class " + c1.GetType() + ": "
+ Type1.GetNumberOfLivingObjects);
Console.WriteLine("existing objects of class " + ws1.GetType() + ": "
+ Type2.GetNumberOfLivingObjects);
Console.WriteLine("existing objects of class C<String>: "
+ C<String>.GetNumberOfLivingObjects);
Console.ReadKey();
}
}
输出是:
existing objects of class C`1[System.Char]: 3
existing objects of class C`1[System.Int32]: 1
existing objects of class C`1[System.Char]: 5
existing objects of class C`1[System.Int32]: 2
existing objects of class C`1[System.Char]: 5
existing objects of class C`1[System.Int32]: 2
existing objects of class C<String>: 20
Destruction of C`1[System.String] number 20
Destruction of C`1[System.String] number 19
Destruction of C`1[System.String] number 18
Destruction of C`1[System.String] number 17
Destruction of C`1[System.String] number 16
Destruction of C`1[System.String] number 15
Destruction of C`1[System.String] number 14
Destruction of C`1[System.String] number 13
Destruction of C`1[System.String] number 12
Destruction of C`1[System.String] number 11
Destruction of C`1[System.String] number 10
Destruction of C`1[System.String] number 9
Destruction of C`1[System.String] number 8
Destruction of C`1[System.String] number 7
Destruction of C`1[System.String] number 6
Destruction of C`1[System.String] number 5
Destruction of C`1[System.String] number 4
Destruction of C`1[System.String] number 3
Destruction of C`1[System.String] number 2
Destruction of C`1[System.String] number 1
编辑: 我的问题是为什么在某些情况下计数器不会下降,而在另一些情况下呢? 为什么Type1和Type2没有在程序结束时调用析构函数,但另一方面,使用String参数化的C调用了析构函数?
答案 0 :(得分:1)
您不能依赖任何垃圾收集器行为。如果你需要析构函数类型的行为,那么让你的类继承IDispose并手动调用Dispose()。
答案 1 :(得分:0)
马克·费尔德曼对他的回答以及他的建议通常做了什么,而不是依赖于垃圾收集器(因为即使明确地称之为GC也太不可靠),因此非常好。
但是对于你的问题:你已经归结为垃圾收集器的主要问题。即使被调用,也无法保证从内存中删除所有不再使用(引用)的变量(对于需要完全不同于其他任何东西的图像,情况更糟)。因此,您正在观察的是GC正在完成其工作,但并不像您期望的那样。
这是你提出这两个问题的唯一原因:为什么有些对象计数会下降而有些则没有(尽管没有引用)。
您可以尝试的一件事是,在致电GC.Collect();
后,您也会致电GC.WaitForPendingFinalizers();
。这可以帮助但遗憾的是,与垃圾收集器一样,它不能100%保证它会有所帮助。
因此,如果您不是绝对有必要使用垃圾收集器(绝对是:如果不消除程序因此而崩溃的异常变量,则使用如此多的内存)那么你应该避免使用它例如Mark Feldman在他的回答中描述的方法。