C# - 需要知道变量何时超出范围

Bet*_*ker 5 c# garbage-collection scope

我有一些C++代码,我正在尝试移植到C#.原作者有一个很酷的缩进调试C++类,其工作原理如下:

void a()
{
   indented_debug id;
   id.trace("I'm in A");
}
void b()
{
   indented_debug id;
   id.trace("I'm in B");
   a();
}
void e()
{
   a();
}
void d()
{
   e();
}
void c()
{
   indented_debug id;
   id.trace("I'm in C");
   a();
   b();
   {
      indented_debug id2;
      id2.trace("I'm still in C");
      d();
   }
}
Run Code Online (Sandbox Code Playgroud)

你在输出中看到的是:

I'm in C
   I'm in A
   I'm in B
      I'm in A
   I'm still in C
      I'm in A
Run Code Online (Sandbox Code Playgroud)

这使得很容易看到不仅调用函数的顺序,而且调用谁的函数.缩进(这是关键的东西)由"indented_debug"对象的构造和销毁自动处理.每次构造一个"indented_debug"对象时,它会递增一个"我应该缩进多少"的计数器; 每次"indented_debug"对象被破坏时,它会递减该计数器.这是自动计算缩进,这是这个类的关键.

当然,C#完全不喜欢这个.C#不遗余力地确保您完全无法知道变量何时超出范围.是的,我知道垃圾收集是如何工作的,我确实喜欢它,但似乎微软可以给我们一个函数IsThisObjectUnreachable()或类似的东西.或者,属性关键字[RefCount]表示"对此对象进行引用计数而不是垃圾回收".

我找不到任何方法来了解一个对象,知道它是否已超出范围,是否有一些聪明的方法在C#中提供相同的功能?

我也应该扔在这个设计限制:我真的宁可不换我的全部功能"使用(indented_debug ID =新的id){}"中,这个想法是有对代码和尽可能少的影响,这个调试功能的可读性是可能的.

[后来添加]

这有点棘手,稍后会像这样添加原始问题,但我需要编写一些代码而不能在评论中这样做.

StackTrace方法与我正在寻找的解决方案非常接近,让我解释它的样子.

public class indented_debug
{
   static int minFrame = 999;
   static void trace(string text)
   {
        StackTrace stackTrace = new StackTrace();
        StackFrame[] frames = stackTrace.GetFrames();

        if (frames.Length < minFrame)
            minFrame = frames.Length;

        String indent = new String(' ', (frames.Length - minFrame) * 3);
        Debug.WriteLine(indent + text);
   }
}
Run Code Online (Sandbox Code Playgroud)

这是非常酷的,因为您甚至不需要构造一个类型为indented_debug的对象 - 缩进完全由您在堆栈中的深度控制.当然,缺点是在我的例子中,当c()调用d()时,在那里有两个额外的堆栈帧,其中没有发生跟踪,因此缩进将超过所需的.Rob通过向方法添加自定义属性提出了一种解决方法,这确实解决了这个问题(我的示例中没有包含他的代码,您可以在下面阅读).

但是还有另一个问题,StackTrace概念不允许在函数内部进行额外的缩进(就像我在原始的c()函数中那样).我认为代码在函数内部有额外缩进的次数非常少,因此在这些情况下添加"using"块可能是可以接受的.这意味着C#代码如下所示:

[IndentLog]
void a()
{
   indented_debug.trace("I'm in A");
}
[IndentLog]
void b()
{
   indented_debug.trace("I'm in B");
   a();
}
void e()
{
   a();
}
void d()
{
   e();
}
[IndentLog]
void c()
{
   indented_debug.trace("I'm in C");
   a();
   b();
   using (indented_debug id = new indented_debug())
   {
      indented_debug.trace("I'm still in C");
      d();
   }
}
Run Code Online (Sandbox Code Playgroud)

然后以确定的方式构造和最终确定对象'id',并且我可以创建一个数据结构,其中我在构造时将'id'与当前堆栈帧相关联,并在最终确定时将其解除关联.