I have C ++ code that I am trying to pass to C #. The original author had a cool C ++ debugging class that works as follows:
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(); } }
And what you see in the output:
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
This makes it very easy to see not only the order in which the functions are called, but also who whom whom. The indentation (which is key here) is automatically handled by the construction and destruction of the "indent_debug" objects. Each time the "indent_debug" object is constructed, it increments the counter "how much should I back off"; every time the indent_debug object is destroyed, it decreases this counter. This is an automatic calculation of the indentation, which is the key to this class.
Of course, C # doesn't like it at all. C # does its best to make sure you are completely unable to find out when the variable is out of scope. And yes, I know how garbage collection works, and I like it, but it looks like Microsoft could provide us with the IsThisObjectUnreachable () function or something like that. Or the keyword attribute [RefCount], which means "Do reference counting on this object instead of garbage collection."
I can’t find a way to find out enough about the object to find out if it goes out of scope, is there any smart way to provide the same functionality in C #?
I should also add to this design restriction: I would prefer not to wrap all my functions when using (indent_debug id = new id) {} ", the idea is to have this debugging feature with minimal impact on the code and its readability .
[Added later]
This is a bit tricky, adding to the original question later, like this, but I need to write some code and can't do it in the comments.
The StackTrace method is oh-so-close to the solution I was looking for, let me explain how it looks.
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); } }
This is great because you don’t even have to create an object like indent_debug - the indentation is completely controlled by how deep you are on the stack. The disadvantage, of course, is that in my example, when c () calls d (), there are two additional stack frames where there is no trace, so the indent will be more than required. Rob suggested this method by adding a custom attribute to the methods that solves this problem (I did not use its code in my example, you can read it below).
But there is another problem: the concept of StackTrace does not allow adding extra indentation inside the function (for example, I have c () in my original function). I thought that the number of times the code has extra padding inside a function is quite small, so it’s probably acceptable to add a “use” block in these cases. This means the C # code looks like this:
[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(); } }
And then the id object is constructed and completed in a deterministic way, and I can create a data structure in which I associate the id with the current frame frame when it constructs, and de-associate it at completion.