C#未收集范围外对象
我正在尝试构建我的第一个单元测试,并拥有一个类,该类分别递增和递减构造函数和析构函数中的实例计数器。我有一个测试来确保它正常工作,但是失败了,我的其他测试中的类的其他实例在超出范围时似乎没有调用它们的析构函数C#未收集范围外对象,c#,unit-testing,garbage-collection,mstest,destructor,C#,Unit Testing,Garbage Collection,Mstest,Destructor,我正在尝试构建我的第一个单元测试,并拥有一个类,该类分别递增和递减构造函数和析构函数中的实例计数器。我有一个测试来确保它正常工作,但是失败了,我的其他测试中的类的其他实例在超出范围时似乎没有调用它们的析构函数 public class Customer { public Customer() { ++InstanceCount; } public Customer(int customerId) { CustomerId
public class Customer
{
public Customer()
{
++InstanceCount;
}
public Customer(int customerId)
{
CustomerId = customerId;
++InstanceCount;
}
~Customer()
{
--InstanceCount;
}
public static int InstanceCount { get; private set; }
}
我没有在任何地方传递引用,所以应该解除分配客户,但事实并非如此,我甚至尝试在StaticTest()的开头调用GC.Collect()来强制调用析构函数,但仍然没有成功
有人能解释为什么会发生这种情况,以及如何修复它。 < P> C不是C++。destructor,或者更确切地说,finalizer,是一种用于非常特定目的的特性,即用于处理对象持有的非托管资源的处置将程序逻辑塞进终结器是使用C#的少数几个非常糟糕的想法之一。为什么?下面是一个简短的概述:
- 当对象超出范围时,无法保证何时收集该对象
- 见鬼,如果没有内存压力,就不能保证会发生收集
- 无法保证对象终结器的运行顺序
- 无法保证对象终结器何时运行—可能是在它超出范围之后,也可能是一分钟之后
- 见鬼,不能保证终结器会运行
- 无法保证,如果它运行,它会在您的ctor完成后运行。因此,在您的情况下,您可能会在不增加实例计数的情况下减少实例计数。诚然,这不太可能真的发生,但也有可能发生
- 哦,它也会对整个应用程序的性能产生负面影响,但与上面的缺点相比,这是相当小的
SafeHandle
如果您需要计算实例,那么最好使用。这是一种协作方式,这意味着调用代码必须实际Dispose()
,才能减少对象的计数。但这不可能是别的方式。底线是,在C#中,当对对象的最后一次引用超出范围时,没有可靠的方法来做某事
更新:
我希望我已经劝阻你永远不要写定稿器,永远。说真的,除非你是一个专业人士,并且确信你绝对需要终结器,并且可以用终结器描述CLR级别上发生的一切,否则不要这样做。然而。有一种丑陋的黑客可以用来得到你想要的东西。这两个咒语:
GC.Collect();
GC.WaitForPendingFinalizers();
应该强制进行收集,这将把对象放在终结器队列上,并等待所有对象完成。如果您在每个测试用例之后都运行它,那么它应该为您提供您期望的行为。但是,为了我们大家,请不要在严肃的代码中使用它。我刚刚给你看了一把非常锋利的双刃剑。没有把手。着火了。第二种方法甚至不能保证终止。< P> C是不是C++。destructor,或者更确切地说,finalizer,是一种用于非常特定目的的特性,即用于处理对象持有的非托管资源的处置将程序逻辑塞进终结器是使用C#的少数几个非常糟糕的想法之一。为什么?下面是一个简短的概述:
- 当对象超出范围时,无法保证何时收集该对象
- 见鬼,如果没有内存压力,就不能保证会发生收集
- 无法保证对象终结器的运行顺序
- 无法保证对象终结器何时运行—可能是在它超出范围之后,也可能是一分钟之后
- 见鬼,不能保证终结器会运行
- 无法保证,如果它运行,它会在您的ctor完成后运行。因此,在您的情况下,您可能会在不增加实例计数的情况下减少实例计数。诚然,这不太可能真的发生,但也有可能发生
- 哦,它也会对整个应用程序的性能产生负面影响,但与上面的缺点相比,这是相当小的
SafeHandle
如果您需要计算实例,那么最好使用。这是一种协作方式,这意味着调用代码必须实际Dispose()
,才能减少对象的计数。但这不可能是别的方式。底线是,在C#中,当对对象的最后一次引用超出范围时,没有可靠的方法来做某事
更新:
我希望我已经劝阻你永远不要写定稿器,永远。说真的,除非你是一个专业人士,并且确信你绝对需要终结器,并且可以用终结器描述CLR级别上发生的一切,否则不要这样做。然而。有一种丑陋的黑客可以用来得到你想要的东西。这两个咒语:
GC.Collect();
GC.WaitForPendingFinalizers();
应该强制执行一个集合,其中w
[TestClass]
public class CustomerTest
{
[TestMethod]
public void FullNameLastNameEmpty()
{
//--Arrange
Customer customer = new Customer {FirstName = "John"};
const string expected = "John";
//--Act
string actual = customer.FullName;
//--Assert
Assert.AreEqual(expected, actual);
}
[TestMethod]
public void StaticTest()
{
//--Arrange
Customer[] customers =
{
new Customer {FirstName = "John"},
new Customer {FirstName = "Jane"},
new Customer {FirstName = "Jeff"}
};
//--Act
//--Assert
Assert.AreEqual(3, Customer.InstanceCount);
}
}
class Program
{
static void Create()
{
Customer[] customers =
{
new Customer (),
new Customer (),
new Customer (),
};
}
static void Main(string[] args)
{
Create();
Console.WriteLine($"Before GC Count: {Customer.InstanceCount}");
GC.Collect(0);
GC.WaitForPendingFinalizers();
Console.WriteLine($"After GC Count: {Customer.InstanceCount}");
}
}