为什么C#中的Counter(带CRTP)没有';对于某些类型的对象,不要倒计时

本文关键字:类型 于某些 对象 倒计时 Counter 中的 CRTP 没有 为什么 | 更新日期: 2023-09-27 18:21:28

我已经在C#计数器中使用CRTP实现了,但我不知道为什么它对某些类型不倒计数:

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却调用了析构函数

为什么C#中的Counter(带CRTP)没有';对于某些类型的对象,不要倒计时

您不能依赖任何垃圾收集器行为。如果需要析构函数类型的行为,那么让类继承IDispose并手动调用Dispose()。

Mark Feldman的回答和建议非常切中要害,通常应该做什么而不是依赖垃圾收集器(因为GC太不可靠了,即使在明确调用时也无法启动)。

但对于你的问题:你的主要问题归结为垃圾收集器。即使被调用,也不能保证它会从内存中删除所有不再使用(引用)的变量(对于需要与其他任何东西完全不同地处理的图像,情况更糟)。因此,您所看到的是GC在做它的工作,但并不像您所期望的那样。

这是你两个问题的唯一原因:为什么有些对象计数下降,而另一些对象计数没有下降(即使没有被引用)。

不过,你可以尝试的一件事是,在你调用GC.Collect();之后,你也会调用GC.WaitForPendingFinalizers();。这可能会有所帮助,但遗憾的是,垃圾收集器并不能100%保证它会有所帮助。

因此,如果你没有绝对必要使用垃圾收集器(绝对是:如果你没有消除程序因此崩溃的不常用变量,你会占用太多内存),那么你应该避免使用它,例如Mark Feldman在他的回答中描述的方法。