CS, __LINE__ unavailability, can we write an alternative? - c#

I'm a Visual C++.net programmer that converted to C# about a year ago, and I really miss __FILE__, and __LINE__. To replace __FILE__, I wrote a nice function to return class.method, which is awesome, but there is no suitable alternative for __LINE__ (correct me if I'm wrong!).
I understand the language difference and technical limitations, and the reasoning, and all that stuff.
What I'm asking is this:
Is it practical, or even possible, to write some visual studio extension (that all of our developers would have installed), that would allow for us to define some type of token (~~LINE~~ or something), that we could have text replacement or something switch that symbol to the actual VS line number, when compiled into an executable?
My knowledge of extensions programming is minimal, I do not know the ext. systems limitations.
Edit for clarification:
In C++, __FILE__, once compiled, will return the current file you wrote your code in, and __LINE__, your current line. This is important because all of our logging systems (10+ years old), all require a char* for the file, and an int for the line, we're logging from.
C# cannot produce these two 'tokens' like C++ can.
As an example:
LoggingService.LogException(e, "file.cs", 1234);
is what I want to get compiled into my executable, and
LoggingService.LogException(e, ~~MYFILE~~, ~~MYLINE~~);
is what I want my code to look like, and saved on disk. I have a suitable alternative to get the file, but I don't have one to get the line.
Edit 2:
These our release builds, without debugging symbols. Our product installs would have to be hundreds of megabytes larger in order to accomidate this fix, which is out of the question.

Caller Information is coming in .NET 4.5. This will be compiled, a big improvment over having to examine the stacktrace manually:
http://msdn.microsoft.com/en-us/library/hh534540(v=vs.110).aspx
public void LogException(Exception ex,
[CallerFilePath] string filePath = "",
[CallerLineNumber] int lineNumber = 0)
{
// Log it!
}
Thanks to the compiler magic, this would be called as:
LoggingService.LogException(e);

You can simply run all C# code through C preprocessor first and than compile results. You will need to change build rules for CS files to do that.

Note: If you are processing exceptions the stack frame is in the exception, so this won't be needed. I used this once to store line and file information with a logging system and that is the only use case I can think of -- but it is "not so fast".
WARNING: If you don't have symbols in your release build some of this information will not be available.
using System;
using System.Diagnostics ;
StackTrace st=new StackTrace (0,true);
StackFrame sf=new StackFrame ();
sf=st.GetFrame (0);
Console.WriteLine ("FileName: {0}",sf.GetFileName ());
Console.WriteLine ("Line Number: {0}",sf.GetFileLineNumber ());
Console.WriteLine ("Function Name: {0}",sf.GetMethod ());
There is also column and type and some other stuff in there... look here for more.
http://msdn.microsoft.com/en-us/library/system.diagnostics.stackframe.aspx

The line is in the exception's stack trace. but rather than extracting it, I think you should log the entire stack trace as it has other useful information for debugging (plus the line number is sometimes a few lines off, due to preprocessor statements i believe)
I would highly recommend ELMAH if you're doing ASP.Net web applications either in Web Forms or MVC. It takes care of all of that logging

Related

How does Exception.StackTrace know lines from my source code?

This confuses me a lot.
My understanding is that when I compile an application it becomes optimized code that my operating system reads. Things from my source code such as variable names, line numbers, etc., no longer have meaning.
So then how am I able to build-and-run code like
try
{
// ...
}
catch ( Exception E )
{
Console.WriteLine("Exception occured: {0}", E.StackTrace);
}
and get all this detailed information about what part of my source code is respomsible for an exception.
Now, I understand that in .NET my C# code doesn't intially become low-level "operating system code" but rather Microsoft Intermediary Language. What I'm guessing it that MIL, in order to generate this exception info, perserves some type of mapping between my source code and the compiled code. This seems like a huge waste, isn't it? So "compiling" in .NET isn't really translating source code to machine code; it is creating machine code in addition to source code. That means that all the applications on my Windows machine have metadata pertraining to their source code.
Or am I completely wrong about all this?
When you compile an assembly the compiler also generates a .pdb file, which is essentially a database file for running your assembly in debug mode. It also contains mappings between the optimized code and the original code, which allows the debugger to know line numbers of methods calls.
Details on .pdb files here: https://msdn.microsoft.com/en-us/library/yd4f8bd1(vs.71).aspx
Stack trace basically contains several parts of information:
Information about what call chain lead to the current execution point. It's not surprise that you can access such information, since when you return from one function, execution should get back to whatever function called it, and so on, up to your program entry point. All function names are also freely available (remember, you can yourself get information about any .NET methods via reflection for example). So this part should not surprise you.
Information about source code file where exception occured, including path to that file (on machine where code was compiled) and line number. This information is stored in separate (.pdb) file, and is optional. If you do not deploy your .pdb files on target machine - you won't see this info in stack traces. You may or may not generate .pdb for your production release, and you may or may not deploy them to target machine.

Debug only paradigm in Lua?

In C/C++ we've had
#ifdef _DEBUG
...
#endif
In C# we've got
#if DEBUG
...
#endif
and
[Conditional("DEBUG")]
I don't expect anything as fancy as an attribute based way of dealing with debug only code but would like to know if there's a manifest constant kind of thing or any other way of making code only present in a debug build. For instance I'm doing the following in Lua at the moment:
if not type(parameters.callback) == 'function' then
error('The "callback" parameter is not a function, or missing (nil).');
end
if not type(parameters.times) == 'number' then
error('The "times" parameter is not a number or missing (nil).');
end
if not type(parameters.interval) == 'number' or not parameters.interval == nil then
error('The "interval" parameter is not a number.');
end
I don't even know if that will run. Totally new to the language.
Given the nature of the function I'm writing, a simple retry function taking the number of attempts to make, an optional interval and a callback as parameters - which I anticipate being used many times throughout the application being written - and that its to be run on a micro controller I feel these checks should not be made in a production release as I'm guessing they could be relatively costly?!?! I'm even doing a type check within a for loop.
Is there already something built into the language to allow for conditional compilation? Or has anyone come up with a neat and clean way of handling this sort of thing? I know I could declare a global variable marking it a debug build and simply put and if block around the above but I thought I'd ask.
Googling has got me nowhere. In fact when I read the sites that talk about Lua I feel like I've stepped back to the mid to late 90's web.
Thanks,
Lee.
EDIT
Or perhaps I just write the method as a C module?!?!
way of making code only present in a debug build
There is no "build" for Lua. It's an interpreted language. Internally it is compiled to byte code, but that's an implementation detail.
However, if you're OK with having a build step, then you can just use a precompiler, exactly as C does. In fact, you can use the same one your your C compiler does, then you're getting the exactly syntax you're already familiar with.
For instance, my old copy of MSVC uses cl /EP <filename> to run filename through the preprocessor and dump the output to stdout. Then you can write:
#ifdef _DEBUG
-- debug Lua code goes here
#endif
The cleanest way would probably be something like
_DEBUG = true
if _DEBUG then
--code
end
The flavour of Lua being used is eLua or Embedded Lua and it does allow pre-compiling scripts to bytecode.
The code is on GitHub so if time permits I'll see about submitting a patch that will allow for true conditional compilation as it's all C under the hood.
In that way everyone benefits. Whether the checks in the original question are costly or not there are often times when you want code in or out depending upon whether you're actively working on it or its being used in a production environment but not the other way around.
And since they support pre-compilation and only target embedded devices with differing levels of performance and memory constraints I wouldn't be surprised if they haven't already implemented support. I'll hop along there and find out next.
Thanks all.

Does Java have 'Debug' and 'Release' build mode like C#?

In C#, we have 2 modes to build projects : Debug and Release, I wonder if Java has the same thing. I am using IntelliJ IDEA as Java IDE and so far I haven't seen anywhere to configure a build mode like in VS IDE.
javac
-g Generate all debugging info
-g:none Generate no debugging info
-g:{lines,vars,source} Generate only some debugging info
You can choose to include debug symbols in the compiled classes (this is the default) or to not do so. There is not much benefit to not doing that. The jar files will be a little smaller, but the performance benefit is minimal (if any). Without these symbols you no longer get line numbers in stack traces. You also have the option to include additional symbols with local variable names (by default there are only source file names and line numbers).
java
-ea[:<packagename>...|:<classname>]
-enableassertions[:<packagename>...|:<classname>]
enable assertions
You can also enable assertions at run-time (default is off), which is sometimes useful during development and testing. This does have a performance impact (if the code in question did indeed make use of assertions, which I think is uncommon).
Regardless of any of these settings, the JVM always allows you to attach a debugger.
What Java does not have is conditional compilation where completely different code would be compiled based on some external setting. The closest you can get is something like public static final boolean DEBUG_BUILD = true; somewhere in your code and use that in if statements. This will actually make the compiler exclude code that becomes unreachable, but you have to set this constant in the source code.
It is normal practice in Java to release everything is a manner which can be debugged. For some projects requiring obfuscation, they could have a release build, but I have never seen this in 12 years of developing Java.
Things such as assertions and debug messages are usually turned off at runtime for a production instance but can be turned on at any time (even dynamically) if required.
IMHO it is best practice to use the same build in every environment, not just the same source but the same JARs. This gives you the best chance that, if it works in test, it will work in production and if you have a problem in production, you can re-produce it in test.
As so much Java code is written this way, the JIT is very good at optimising dead code which is never called. So much so that IMHO most of the micro-"benchmarks" where Java out performs C++, is when the benchmark doesn't do any thing and the JIT is better at detecting this. IMHO, C++ assumes the developer is smart enough not to write code which doesn't do anything.
You're asking for different kinds of builds to compile in different things I guess. For example to have Debug.WriteLine and Console.WriteLine.
"No, Java doesn't have an exact match for that functionality. You could use aspects, or use an IOC container to inject different implementation classes." stole this from the following question: Conditional Java compilation
(there're other nice answers for you there)

If I insert a comment on a source code will it`s binarries MD5 be changed?

I`m just wondering....
If it was the case that I was thinking in creating different reseases for each custumer that I sold my software, could I check each one with MD5 just changing a comment inside the source code and recompiling? I mean, will a ##comment inside a C++, C# or java code change the binnary MD5?
Comments are removed early in (or before) the compilation process, so inserting a comment will not change the hash of the compiled binary.
The only exception (that I can think of) is if your binaries include line numbers, which can change based on comments. Typically this happens when you're compiling in debug mode, but you can also force it using something like the __LINE__ macro in C++. But even in this case, the content of the comment is irrelevant, only how many lines it takes up (so you might as well just use blank lines for that purpose). Besides, released software probably shouldn't include that information.
Short answer is no. Comments are stripped out very early in the compilation process.
The longer answer is, sometimes - but not reliably. There's a number of foreseeable reasons that vestiges (more like side-effects) of the comment could show up. However, those are fragile at best.
I assume this is for some sort of automated process, like selling the software on a website. How about outputting a header file like "user.h" that simply specifies the name/email/username/etc as a #define'd string, and then printing that somewhere in your program's About screen (both for the user's benefit and so the compiler doesn't optimize it away)? It requires you to recompile your program for each user, but that may not be a problem if it only takes a few seconds to build.
In some cases, the binary changes for every build, if there is for instance a build timestamp. This could provide the traceability you want. However, comments should not affect the MD5 of a release mode binary, unless your compiler is buggy.
A comment cannot be compiled to a cpu opcode so it will not change the hash of the blob.
Yes it can change the binaries.
For example in C/C++ there's the LINE macro for instance. If this is used in the code it will change the binary if you add or remove a line with comment.

What happens if we add lines to IL code and add breakpoints to our program?

If I add let's say 1 line at the beggining of a method, if I set a breakpoint through Visual Studio on the first line, will it point to the first line or the second? If it will flag the wrong line, is there anything we could do when editing .exe files to ensure a regular debugging session later?
Isn't there something like setting line x to be Y? I remember seeing something like that somewhere, not sure if .NET related or not.
You'll need to update the debugging symbols in the PDB file if you want the debugging experience to remain unchanged.
The best option for this I've seen is to use Mono.Cecil, as it supports (limited) modification of the debugging symbols as well as the IL.
If you are modifying IL then the PDB files will contain outdated information. Note that there probably won't be a 1:1 between changes in IL lines to the C# line #s (eg inserting 3 IL statements won't offset the IDE breakpoint by 3 lines of C#).
You may want to separate the IL-modified portions of your code into separate methods to minimize the impact. Also, assuming you are the one doing the IL modification, you may find it convenient to switch between the C# & IL views while debugging.
You might need to muck a bit with the generated code to facilitate that. For example, if the injected IL can be in a wrapper method then you could tell the debugger to ignore it by usage of attrbiutes such as DebuggerStepThroughAttribute, DebuggerNonUserCodeAttribute, or DebuggerHiddenAttribute. (Look up the documentation for the nuances in behavior)
I expect that you get flagged as .pdb file might not match.
How are you adding the IL? If you are doing this via profiler instrumentation (SetILFunctionBody) then you need to supply a new IL code map as well (SetILInstrumentationCodeMap) so that the debugger becomes aware of the IL modification.

Categories

Resources