gpt4 book ai didi

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

转载 作者:太空狗 更新时间:2023-10-29 23:05:59 25 4
gpt4 key购买 nike

我有一些要移植到 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();
}
}

你在输出中看到的是这样的:

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

这使得不仅可以很容易地看到调用函数的顺序,而且可以很容易地看到谁在调用谁。缩进(这是这里的关键)由“indented_debug”对象的构造和销毁自动处理。每次构造“indented_debug”对象时,它都会增加一个“我应该缩进多少”计数器;每次销毁“indented_debug”对象时,它都会递减该计数器。缩进的自动计算是该类(class)的关键。

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

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

我还应该加入这个设计限制:我真的不想把我所有的函数都包装在“using (indented_debug id = new 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);
}
}

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

但还有另一个问题,StackTrace 概念不允许在函数内进行额外的缩进(就像我在原来的 c() 函数中那样)。我在想代码在函数中有额外缩进的次数非常少,所以在这些情况下添加“using” block 可能是可以接受的。这意味着 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();
}
}

然后对象“id”以确定的方式构造和完成,我可以创建一个数据结构,在构造时将“id”与当前堆栈帧相关联,并在完成时取消关联。

最佳答案

IDisposable 接口(interface)是在 C# 中使用的机制,当您需要在不再需要某个对象时确定性地执行某些操作。所以它不像 C++ 那样精简,但它肯定可以做类似的事情:

void a()
{
using(var id = new IndentedDebug())
{
id.trace("I'm in A");
}
}
void b()
{
using(var id = new IndentedDebug())
{
id.trace("I'm in B");
a();
}
}

并将引用计数添加到 IndentedDebug.Dispose 方法。

使用 AOP 或其他模式可能有更好的方法,但可能在变量超出范围时执行某些操作。

关于C# - 需要知道变量何时超出范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36796820/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com