Do __LINE__ __FILE__ equivalents exist in C#? - c#

For logging purposes
__LINE__
__FILE__
were my friends in C/C++. In Java to get that information I had to throw an exception and catch it. Why are these old standbys so neglected in the modern programming languages? There is something magical about their simplicity.

Caller Information has been added to .NET 4.5. This will be compiled, a big improvement over having to examine the stack trace manually.
public void Log(string message,
[CallerFilePath] string filePath = "",
[CallerLineNumber] int lineNumber = 0)
{
// Do logging
}
Simply call it in this manner. The compiler will fill in the file name and line number for you:
logger.Log("Hello!");

It is uglier, but you can do something like this in C# using the StackTrace and StackFrame classes:
StackTrace st = new StackTrace(new StackFrame(true));
Console.WriteLine(" Stack trace for current level: {0}", st.ToString());
StackFrame sf = st.GetFrame(0);
Console.WriteLine(" File: {0}", sf.GetFileName());
Console.WriteLine(" Method: {0}", sf.GetMethod().Name);
Console.WriteLine(" Line Number: {0}", sf.GetFileLineNumber());
Console.WriteLine(" Column Number: {0}", sf.GetFileColumnNumber());
Of course, this comes with some overhead.

With Caller Information (introduced in .NET 4.5) you can create the equivalent of __LINE__ and __FILE__ in C#:
static int __LINE__([System.Runtime.CompilerServices.CallerLineNumber] int lineNumber = 0)
{
return lineNumber;
}
static string __FILE__([System.Runtime.CompilerServices.CallerFilePath] string fileName = "")
{
return fileName;
}
The only thing to remember is that these are functions and not compiler directives.
So for example:
MessageBox.Show("Line " + __LINE__() + " in " + __FILE__());
If you were to use this in practise then I'd suggest different names. I've used the C/C++ names just to make it clearer what they are returning, and something like CurrentLineNumber() and CurrentFileName() might be better names.
The advantage of using Caller Information over any solution that uses the StackTrace is that the line and file information is available for both debug and release.

The closest thing to those is the fact that you can create a StackTrace object and find out the name of the method at the top of the stack, so you can get close to the functionality of the __FUNCTION__ macro.
StackTrace stackTrace = new StackTrace();
StackFrame[] stackFrames = stackTrace.GetFrames();
foreach (StackFrame stackFrame in stackFrames)
Console.WriteLine(stackFrame.GetMethod().Name);
To reduce the cost of typing this out by hand, and also the runtime code, you can write a helper method:
[Conditional("Debug")]
public void LogMethodName()
{
Trace.WriteLine("Entering:" + new StackTrace().GetFrame(1).GetMethod().Name);
}
Note how we get frame 1, as frame 0 would be LogMethodName itself. By marking it as Conditional("Debug") we ensure that the code is removed from release builds, which is one way to avoid the runtime cost where it may not be needed.

Because the stack trace contains most of what you need. It will not give you the name of the file but it will give you the class/method name. It also contains the line number. It is not neglected it is automatic. You just need to throw an exception like you do it in Java

Here's a way to get the line number: http://askville.amazon.com/SimilarQuestions.do?req=line-numbers-stored-stack-trace-C%2523-application-throws-exception
If you use log4net, you can get the line number and file name in your logs, but:
it can decrease your app. performance
you have to have .PDB files together with your assemblies.

There are already some suggestions to achieve what you want. Either use the StackTrace object or better log4net.
In Java to get that information I had to throw an exception and catch it.
That's not quite true. You can have it without throwing exceptions, too. Have a look to log4j. It even logs your method and class name, without polluting your code with hard coded strings containing the current method name (at least I have seen this in some occasions).
Why are these old standbys so neglected in the modern programming languages?
Java and C# don't make use (in the latter: excessive use) of preprocessors. And I think it's good. Abusing preprocessors to make unreadable code is very easy. And if programmers can abuse some technique ... they will abuse it.
Just a note about performance, which is very likely to be the next thing, which pops up in your mind:
If you use StackTrace or log4net you will always will read or hear that it is slow, because it uses Reflection. I am using log4net and I never encountered logging as a performance bottle neck. If it would be, I can declaratively deactivate (parts of) logging -- without changing the source code. That's pure beauty compared to delete all the logging lines in C/C++ code! (Besides: If performance is a primary goal, I would use C/C++ ... it will never die despite of Java and C#.)

Having used the FILE and LINE macros for many years for logging in C/C++ I really wanted a similar solution in C#. This is my solution. I prefer it to #fostandy suggestion of creating many overloads with varying number of parameters. This seems the less intrusive and does not limit the number of formatted parameters. You just have to be willing to accept the addition of the F.L() parameter at start of every Log.Msg() call.
using System;
using System.Runtime.CompilerServices;
namespace LogFileLine
{
public static class F
{
// This method returns the callers filename and line number
public static string L([CallerFilePath] string file = "", [CallerLineNumber] int line = 0)
{
// Remove path leaving only filename
while (file.IndexOf("\\") >= 0)
file = file.Substring(file.IndexOf("\\")+1);
return String.Format("{0} {1}:", file, line);
}
}
public static class Log
{
// Log a formatted message. Filename and line number of location of call
// to Msg method is automatically appended to start of formatted message.
// Must be called with this syntax:
// Log.Msg(F.L(), "Format using {0} {1} etc", ...);
public static void Msg(string fileLine, string format, params object[] parms)
{
string message = String.Format(format, parms);
Console.WriteLine("{0} {1}", fileLine, message);
}
}
class Program
{
static void Main(string[] args)
{
int six = 6;
string nine = "nine";
string dog = "dog";
string cat = "cats";
Log.Msg(F.L(), "The {0} chased the {1} {2}", dog, 5, cat);
Log.Msg(F.L(), "Message with no parameters");
Log.Msg(F.L(), "Message with 8 parameters {0} {1} {2} {3} {4} {5} {6} {7}",
1, 2, 3, "four", 5, 6, 7, 8.0);
Log.Msg(F.L(), "This is a message with params {0} and {1}", six, nine);
}
}
}
Here's the output from this code above
Program.cs 41: The dog chased the 5 cats
Program.cs 43: Message with no parameters
Program.cs 45: Message with 8 parameters 1 2 3 four 5 6 7 8
Program.cs 48: This is a message with params 6 and nine

Related

Pulling specific information from C# WinForms error messages

I have a logging system set up in my C# WinForms project that writes to a log txt file. A typical error message looks like this:
Error :
8:34:48 AM Tuesday, April 21, 2020
:
:System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
at System.Collections.ArrayList.get_Item(Int32 index)
at System.Windows.Forms.DataGridViewColumnCollection.get_Item(Int32 index)
at CrossReferenceTool.frmXRefTool.DefineControlsLayout() in <PathToSourceCsFile>:line 306
Is there any way to grab parts of that error message? Specifically, I'd like to pull the offending method (DefineControlsLayout() in this case) and the line number.
Instantiate a new StackTrace and go log the details from that after any exception occurs.
Original link I used: https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.stacktrace.getframe?view=netframework-4.8
Example code
using System.Diagnostics;
try
{
throw new Exception("Fail");
}
catch (Exception e)
{
StackTrace st = new StackTrace(e);
// Display the most recent function call.
StackFrame sf = st.GetFrame(0);
Console.WriteLine();
Console.WriteLine(" Exception in method: ");
Console.WriteLine(" {0}", sf.GetMethod());
if (st.FrameCount > 1)
{
// Display the highest-level function call
// in the trace.
sf = st.GetFrame(st.FrameCount - 1);
Console.WriteLine(" Original function call at top of call stack):");
Console.WriteLine(" {0}", sf.GetMethod());
// will only work if .pdb is included
var lineNumber = sf.GetFileLineNumber();
var fileName = sf.GetFileName();
}
}
If you are already catching an Exception type then you have sub properties such as
Exception.StackTrace
Exception.TargetSite
I don't think that you can use them to pull the line of code though.

Checking the values of a long string from a specific point

This is a follow on from my last question.
The string I am trying to compare comes through as follows:
Discovered Peripherial: <CBPeripheral: 0x39b8b50 identifier = DEEE65FB-FF1F-A6A9-4C3C-5784F41B0D39, Name = "rawr", state = connecting>
What I'm trying to do is check the identifier number to that which I'm storing in my program. To do that, I have done the following:
private void AppendString(string message)
{
message.Substring(message.Length-77, message.Length);
outputContent.text += "\n" + message;
}
The \n is in there because I'm reading in 6 different devices and they all generate the above line. So I needed something to make it easier to read.
Then in my update function I am checking to see if they are similar like so:
if(String.Equals(myValues["UUID"], outputContent.text, StringComparison.OrdinalIgnoreCase))
{
Instantiate(model1, new Vector3(-2.5f, 3.0f,0), Quaternion.identity);
}
However when I run this on my iPad, xCode generates the following message:
ArgumentOutOfRangeException: startIndex + length > this.length
Parameter name: length
Which I'm guessing means I have miscounted the amount of characters I need to count back from in the substring.
My question is this:
Is there a better way in which I can compare my stored value with that of a specific part of a really long string or have I done something silly in my code which is generating that error?
This is a Unity project which I'm building onto an iPad and makes use of some functionality I can't replicate on a mac.
in your code i observed that you are calling Substring() method but not getting/saving its result into some variable .
message.Substring(message.Length-77, message.Length);
as string is an immutable which can not be modified.
hence when you call the Substring() method it cuts the required text and returns, which you have to save it on some variable to proceed further.
as below:
replace your function AppendString() as below :
private void AppendString(string message)
{
message= message.Substring(message.Length-77, message.Length);
outputContent.text += "\n" + message;
}

Search String takes a long time the first time only?

No shortage of search for string performance questions out there yet I still can not make heads or tails out of what the best approach is.
Long story short, I have committed to moving from 4NT to PowerShell. In leaving the 4NT I am going to miss the console super quick string searching utility that came with it called FFIND. I have decided to use my rudimentary C# programming skills to try an create my own utility to use in PowerShell that is just as quick.
So far search results on a string search in 100's of directories across a few 1000 files, some of which are quite large, are FFIND 2.4 seconds and my utility 4.4 seconds..... after I have ran mine at least once????
The first time I run them FFIND does it near the same time but mine takes over a minute? What is this? Loading of libraries? File indexing? Am I doing something wrong in my code? I do not mind waiting a little longer but the difference is extreme enough that if there is a better language or approach I would rather start down that path now before I get too invested.
Do I need to pick another language to write a string search that will be lighting fast
I have the need to use this utility to search through 1000 of files for strings in web code, C# code, and another propitiatory language that uses text files. I also need to be able to use this utility to find strings in very large log files, MB size.
class Program
{
public static int linecounter;
public static int filecounter;
static void Main(string[] args)
{
//
//INIT
//
filecounter = 0;
linecounter = 0;
string word;
// Read properties from application settings.
string filelocation = Properties.Settings.Default.FavOne;
// Set Args from console.
word = args[0];
//
//Recursive search for sub folders and files
//
string startDIR;
string filename;
startDIR = Environment.CurrentDirectory;
//startDIR = "c:\\SearchStringTestDIR\\";
filename = args[1];
DirSearch(startDIR, word, filename);
Console.WriteLine(filecounter + " " + "Files found");
Console.WriteLine(linecounter + " " + "Lines found");
Console.ReadKey();
}
static void DirSearch(string dir, string word, string filename)
{
string fileline;
string ColorOne = Properties.Settings.Default.ColorOne;
string ColorTwo = Properties.Settings.Default.ColorTwo;
ConsoleColor valuecolorone = (ConsoleColor)Enum.Parse(typeof(ConsoleColor), ColorOne);
ConsoleColor valuecolortwo = (ConsoleColor)Enum.Parse(typeof(ConsoleColor), ColorTwo);
try
{
foreach (string f in Directory.GetFiles(dir, filename))
{
StreamReader file = new StreamReader(f);
bool t = true;
int counter = 1;
while ((fileline = file.ReadLine()) != null)
{
if (fileline.Contains(word))
{
if (t)
{
t = false;
filecounter++;
Console.ForegroundColor = valuecolorone;
Console.WriteLine(" ");
Console.WriteLine(f);
Console.ForegroundColor = valuecolortwo;
}
linecounter++;
Console.WriteLine(counter.ToString() + ". " + fileline);
}
counter++;
}
file.Close();
file = null;
}
foreach (string d in Directory.GetDirectories(dir))
{
//Console.WriteLine(d);
DirSearch(d,word,filename);
}
}
catch (System.Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
}
If you want to speed up your code run a performance analysis and see what is taking the most time. I can almost guaruntee the longest step here will be
fileline.Contains(word)
This function is called on every line of the file, on every file. Naively searching for a word in a string can taken len(string) * len(word) comparisons.
You could code your own Contains method, that uses a faster string comparison algorithm. Google for "fast string exact matching". You could try using a regex and seeing if that gives you a performance enhancement. But I think the simplest optimization you can try is :
Don't read every line. Make a large string of all the content of the file.
StreamReader streamReader = new StreamReader(filePath, Encoding.UTF8);
string text = streamReader.ReadToEnd();
Run contains on this.
If you need all the matches in a file, then you need to use something like Regex.Matches(string,string).
After you have used regex to get all the matches for a single file, you can iterate over this match collection (if there are any matches). For each match, you can recover the line of the original file by writing a function that reads forward and backward from the match object index attribute, to where you find the '\n' character. Then output that string between those two newlines, to get your line.
This will be much faster, I guarantee it.
If you want to go even further, some things I've noticed are :
Remove the try catch statement from outside the loop. Only use it exactly where you need it. I would not use it at all.
Also make sure your system is running, ngen. Most setups usually have this, but sometimes ngen is not running. You can see the process in process explorer. Ngen generates a native image of the C# managed bytecode so the code does not have to be interpreted each time, but can be run natively. This speeds up C# a lot.
EDIT
Other points:
Why is there a difference between first and subsequent run times? Seems like caching. The OS could have cached the requests for the directories, for the files, for running and loading programs. Usually one sees speedups after a first run. Ngen could also be playing a part here, too, in generating the native image after compilation on the first run, then storing that in the native image cache.
In general, I find C# performance too variable for my liking. If the optimizations suggested are not satisfactory and you want more consistent performance results, try another language -- one that is not 'managed'. C is probably the best for your needs.

String FormatException

I'm doing an activity that asks your name, and if a number is inserted it should tell that the input is invalid.
Here's my code:
try {
Console.Write("Enter your first name: ");
string fname = Console.ReadLine();
Console.Write("You're Name is: " + fname);
}
catch (Exception) {
Console.Write("INVALID NAME");
}
Sample output:
Enter you're first name: 123hjay
INVALID NAME!!
I know my exception is wrong; I need your help guys.
You seem to have misunderstood the purpose of exceptions.
Exceptions are thrown when a program encounters an error in its execution. For example assigning a letter to an int would throw an error. While opinions vary, I tend not to handle user input errors with exceptions. Furthermore, think about the logic you wrote in your code. How could the program know that entering numbers into a variable named fname is incorrect?
Write in logic into your program to test for input errors and then return an appropriate response. In your case, if you wanted to ensure that there were no numbers entered, you could do the following:
if (name.Any(char.IsNumber))
{
Console.WriteLine("Invalid Name.");
}
Console.ReadLine();
As my comment says (in the question), I didn't really get what it is you are asking, because it doesn't throw anything, but if you did want it to throw an error (also suggested by the comments), this should help:
Console.Write("Enter you're first name: ");
string fname = Console.ReadLine();
foreach (var character in fname)
{
if (Char.IsDigit(character))
throw new Exception("Numbers are not allowed.");
}
Console.Write("You're Name is: " + fname);
It's very straight forward and you can read it as English and understand what I've done.
You can mess around with the code, look at similar functions with Visual Studios IntelliSense and tweak it to your needs.
If you need, add a try & catch blocks, of course.
for the courtesy of replying back, here is the answer.
Hint: your exception is right!
Enter in your console "Glee" it will not throw exception.
If you type "7337" it does throw exception.
try to use : fname.ToString();

Writing to the console from a method .NET 4.0

The following is a short clock program from the book "programming in the key of c#". I'm not familiar with the Timers library at all so some of this syntax I don't really get. What I want to understand and I don't is the line Console.Write(str) in the method in this little program. How does Main know what to print to the console? Is it the empty Console.WriteLine() call that makes the time print out every second? When I'm reading about these concepts it seems easy after the fact to understand what's going on. Based on what I've asked, what are the things about C# that I don't really understand yet?
using System;
using System.Timers; // Requires System.dll
class Clock
{
static int iStringLength;
static void Main()
{
Console.WriteLine("Press Enter to end program");
Console.WriteLine();
Timer tmr = new Timer();
tmr.Elapsed += new ElapsedEventHandler(TimerHandler);
tmr.Interval = 1000;
tmr.Start();
Console.ReadLine();
tmr.Stop();
}
static void TimerHandler(object obj, ElapsedEventArgs eea)
{
Console.Write(new String('\b', iStringLength));
string str = String.Format("{0} {1} ",
eea.SignalTime.ToLongDateString(),
eea.SignalTime.ToLongTimeString());
iStringLength = str.Length;
Console.Write(str);
}
}
Main() doesn't print anything to the console, except for the initial blank line.
Console.Write() in the TimerHandler() callback runs every second and prints the time.
str contains the value of the string after the String.Format() function is called. That function is documented here: http://msdn.microsoft.com/en-us/library/b1csw23d.aspx
In your code, the {0} is replaced by the formatted representation of eea.SignalTime.ToLongDateString(), and the {1} is replaced by a formatted representation of eea.SignalTime.ToLongTimeString().
So to answer
What I want to understand and I don't is the line Console.Write(str)
in the method in this little program. How does Main know what to print
to the console?
the answer is "It writes whatever the String.Format() function has determined the value of "str" is in this line:"
string str = String.Format("{0} {1} ",
eea.SignalTime.ToLongDateString(),
eea.SignalTime.ToLongTimeString());
The WriteLine() function just prints an empty line and really has nothing to do with the string that shows the date/time as you asked.
For the record, Console.Write and Console.Writeline are documented here and here, respectively.
Console.WriteLine() without any parameters does exactly what it sounds like, just prints out an empty line (newline).
Writes the current line terminator to the standard output stream.
Console.WriteLine(xxx) with any parameter prints the parameter on a line, followed by a new line.
Writes the specified data, followed by the current line terminator, to
the standard output stream.
In your TimerHandler method, you are using Console.Write(xxx), which just prints the text representation of the parameter, without a newline.
Writes the text representation of the specified object to the standard
output stream.

Categories

Resources