I am writing a language of my own called SPL. It has an Input command which reads input from the ISplRuntime.Input property (it is a TextReader). All other commands run on this interface because this way I can write different apps with just one library!
I then wrote another console app to test my language. This is my implementation of ISplRuntime. Focus on the Input and constructor:
public class MyRuntime : ISplRuntime {
protected TextReader reader;
protected bool stopped;
public object Current {
get;
set;
}
public virtual TextReader Input {
get {
return reader;
}
}
public object[] Memory {
get;
protected set;
}
public TextWriter Output {
get {
return Console.Out;
}
}
public bool Stopped {
get {
return stopped;
}
set {
stopped = value;
if (value) {
Console.WriteLine ();
Console.WriteLine ("Program has finished");
}
}
}
public void ShowErrorMessage (string error) {
Console.WriteLine (error);
}
public MyRuntime () {
string s = Console.ReadLine ();
reader = new StringReader (s);
stopped = false;
Memory = new object[20];
}
}
When the runtime is constructed, it asks for input. And use that input to create a StringReader and return it in the Input property. So every time the input will only be one lline.
Then I write a program in SPL that outputs the input. And that is where the problem is! When I input 1 1 1 1 it prints 1 1 1 and threw a FormatException. This is how I read number input:
private bool ReadFromInput (ISplRuntime runtime, out int i) {
char stuffRead = (char)runtime.Input.Peek ();
if (stuffRead == ' ') {
i = 0;
runtime.Input.Read ();
return true;
}
if (char.IsNumber (stuffRead)) {
string numberString = "";
while (char.IsNumber (stuffRead)) {
stuffRead = (char)runtime.Input.Read ();
numberString += stuffRead;
}
i = Convert.ToInt32 (numberString); //This is where the exception occured! (Obviously, because there is no other methods that would throw it)
return true;
} else {
i = 0;
return false;
}
}
The parameter runtime is just the runtime you have just seen. It returns true if it successfully reads a number. And that number is the output parameter i.
After using the "Watch" window in Visual Studio, I found out that number string is "1\uffff" when the exception is thrown. That's why it throws it! I know (think) that '\uffff' is the end of line character. But why would it appear in my input? I know (think) that pressing Ctrl + Z makes a end of line, but I did not! Then I checked runtime.Input in the watch window. This is the result:
I see that there is a field called _s and I think that is the string that I told it to read from. See? _s doesn't even contain '\uffff', how come it reads it?
P.S. I already know the solution. I just need to change the while loop a little and it works. But I want to know why does it reads an end of line.
There is no mistery here - \uffff is produced by your code. All you need is to read the documentation and understand what the methods that you call return.
TextReader.Peek Method
Return Value
Type: System.Int32
An integer representing the next character to be read, or -1 if no more characters are available or the reader does not support seeking.
TextReader.Read Method
Return Value
Type: System.Int32
The next character from the text reader, or -1 if no more characters are available.
Hope you see the relation between -1 (0xffffffff) and \uffff.
Related
I am trying to convert the text in the console and reverse it to see if it is a palindrome. If it is, then it will return true and if it is not, then false will be returned. However, I am facing errors since I am new and just started to learn C#. The error that I get is as follows:
'Palindrome.IsPalindrome(string)': not all code paths return a value
I don't know how to solve this and I dont quite understand it, hence any advice would be very much appreciated. Thank You.
using System;
public class Palindrome
{
public static bool IsPalindrome(string word)
{
char[] temp = word.ToCharArray();
Array.Reverse(temp);
string emordnilap = new string(temp);
if(word.Equals(emordnilap)){
Console.WriteLine("true");
}else{
Console.WriteLine("false");
}
}
public static void Main(string[] args)
{
Console.WriteLine(Palindrome.IsPalindrome("Deleveled"));
}
}
Your method is defined as public static bool IsPalindrome(string word)
That means it must return a boolean (true or false).
You're not actually returning anything, you're just writing it out to the console, and that's what your error is - you're not returning a value.
You need to put return true; or return false; in your code so that every possible route through the method results in it returning the bool you specified in the method signature.
This gives you another issue, because you're doing Console.WriteLine(_) where _ is the return value of your IsPalindrome method. Since you're returning a bool then it's strange to write that to the console. It will work, but a better way to do this would be call to the method like this:
var isPalindrome = Palindrome.IsPalindrome("Deleveled");
if (isPalindrome == true)
{
Console.WriteLine("It IS a palindrome!");
}
Note that if (isPalindrome == true) can be shortened to if (isPalindrome)
One of the core aspects of OO programming is SOLID, which are some guidelines for writing code. One of those is the Single Responsibility Principle, which basically means you should try to make bits of your code only do one thing.
So it's better for your IsPalindrome to only do one thing - return true or false if the word is a palindrome - and not do other things such as writing to the console. Leave that for the code that is calling the method.
Just a hint for when your method unexpectedly returns false - Racecar is not the same as racecaR - you will have to do something about the case. A quick way to do this is with ToUpper() to convert your value to upper case before you reverse it and do the comparison.
Your method should return a bool instead of writing to Console. Try like:
public static bool IsPalindrome(string word)
{
char[] temp = word.ToCharArray();
Array.Reverse(temp);
string emordnilap = new string(temp);
if(word.Equals(emordnilap)){
return true;
}
else{
return false;
}
}
Every path this method can take to get to its end, has to return a boolean value:
using System;
public class Palindrome
{
public static bool IsPalindrome(string word)
{
char[] temp = word.ToCharArray();
Array.Reverse(temp);
string emordnilap = new string(temp);
if(word.Equals(emordnilap))
{
return true;
}
else
{
return false;
}
}
public static void Main(string[] args)
{
//The ToString() converts your boolean to a string
Console.WriteLine(Palindrome.IsPalindrome("Deleveled").ToString());
}
}
Try naming your Variables more understandably. That will make your live easier if you get into bigger projects. See here
what is proper way to save all lines from text file to objects. I have .txt file something like this
0001Marcus Aurelius 20021122160 21311
0002William Shakespeare 19940822332 11092
0003Albert Camus 20010715180 01232
From this file I know position of each data that is written in file, and all data are formatted.
Line number is from 0 to 3
Book author is from 4 to 30
Publish date is from 31 to 37
Page num. is from 38 to 43
Book code is from 44 to 49
I made class Data which holds information about start, end position, value, error.
Then I made class Line that holds list of type Data, and list that holds all error founded from some line. After load data from line to object Data I loop through lineError and add errors from all line to list, because I need to save errors from each line to database.
My question is this proper way to save data from file to object and after processing same data saving to database, advice for some better approach?
public class Data
{
public int startPosition = 0;
public int endPosition = 0;
public object value = null;
public string fieldName = "";
public Error error = null;
public Data(int start, int end, string name)
{
this.startPosition = start;
this.endPosition = end;
this.fieldName = name;
}
public void SetValueFromLine(string line)
{
string valueFromLine = line.Substring(this.startPosition, this.endPosition - this.startPosition);
// if else statment that checks validity of data (lenght, empty value)
this.value = valueFromLine;
}
}
public class Line
{
public List<Data> lineData = new List<Data>();
public List<Error> lineError = new List<Error>();
public Line()
{
AddObjectDataToList();
}
public void AddObjectDataToList()
{
lineData.Add(new Data(0, 3, "lineNumber"));
lineData.Add(new Data(4, 30, "bookAuthor"));
lineData.Add(new Data(31, 37, "publishData"));
lineData.Add(new Data(38, 43, "pageNumber"));
lineData.Add(new Data(44, 49, "bookCode"));
}
public void LoadLineDataToObjects(string line)
{
foreach(Data s in lineData)
{
s.SetValueFromLine(line);
}
}
public void GetAllErrorFromData()
{
foreach (Data s in lineData)
{
if(s.error != null)
{
lineError.Add(s.error);
}
}
}
}
public class File
{
public string fileName;
public List<Line> lines = new List<Line>();
}
I assume that the focus is on using OOP. I also assume that parsing is a secondary task and I will not consider options for its implementation.
First of all, it is necessary to determine the main acting object. Strange as it may seem, this is not a Book, but the string itself (e.g. DataLine). Initially, I wanted to create a Book from a string (through a separate constructor), but that would be a mistake.
What actions should be able to perform DataLine? - In fact, only one - process. I see two acceptable options for this method:
process returns Book or throws exceptions. (Book process())
process returns nothing, but interacts with another object. (void process(IResults result))
The first option has the following drawbacks:
It is difficult to test (although this applies to the second option). All validation is hidden inside DataLine.
It is impossible/difficult to return a few errors.
The program is aimed at working with incorrect data, so expected exceptions are often generated. This violates the ideology of exceptions. Also, there are small fears of slowing performance.
The second option is devoid of the last two drawbacks. IResults can contain methodserror(...), to return several errors, and success(Book book).
The testability of the process method can be significantly improved by adding IValidator. This object can be passed as a parameter to the DataLine constructor, but this is not entirely correct. First, this unnecessary expense of memory because it will not give us tangible benefits. Secondly, this does not correspond to the essence of the DataLine class. DataLine represents only a line that can be processed in one particular way. Thus, a good solution is the void process (IValidator validator, IResults result).
Summarize the above (may contain syntax errors):
interface IResults {
void error (string message);
void success (Book book);
}
interface IValidator {
// just example
bool checkBookCode (string bookCode);
}
class DataLine {
private readonly string _rawData;
// constructor
/////////////////
public void process (IValidator validator, IResults result) {
// parse _rawData
bool isValid = true; // just example! maybe better to add IResults.hasErrors ()
if (! validator.checkBookCode (bookCode)) {
result.error("Bad book code");
isValid = false;
}
if (isValid) {
result.success(new Book (...));
// or even result.success (...); to avoid cohesion (coupling?) with the Book
}
}
}
The next step is to create a model of the file with the lines. Here again there are many options and nuances, but I would like to pay attention to IEnumerable<DataLine>. Ideally, we need to create a DataLines class that will support IEnumerable<DataLine> and load from a file or from IEnumerable<string>. However, this approach is relatively complex and redundant, it makes sense only in large projects. A much simpler version:
interface DataLinesProvider {
IEnumerable <DataLine> Lines ();
}
class DataLinesFile implements DataLinesProvider {
private readonly string _fileName;
// constructor
////////////////////
IEnumerable <DataLine> Lines () {
// not sure that it's right
return File
. ReadAllLines (_fileName)
.Select (x => new DataLine (x));
}
}
You can infinitely improve the code, introduce new and new abstractions, but here you must start from common sense and a specific problem.
P. S. sorry for "strange" English. Google not always correctly translate such complex topics.
In my C# Windows Forms application using Firefox Selenium WebDriver I need to check if an element exists and if it doesn't, click a different one. If there is a video, after it is watched it becomes W_VIEWED:
driver.FindElement(By.XPath("//div[#class='video']/a")).Click();
else
{
driver.FindElement(By.XPath("//div[#class='W_VIEWED']/a")).Click();
}
Error 3 Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement 242
You can check if an element exits or not by using
bool isElementDisplayed = driver.findElement(By.xpath("element")).isDisplayed()
Remember, findElement throws an exception if it doesn't find an element, so you need to properly handle it.
In one of my applications, I handled an exception by checking the element in a separate function:
private bool IsElementPresent(By by)
{
try
{
driver.FindElement(by);
return true;
}
catch (NoSuchElementException)
{
return false;
}
}
Call function:
if (IsElementPresent(By.Id("element name")))
{
// Do if exists
}
else
{
// Do if does not exists
}
You can use FindElements with an "s" to determine if it exists, since FindElement results in an Exception. If FindElements does not return an element then it returns an empty list.
List<IWebElement> elementList = new List<IWebElement>();
elementList.AddRange(driver.FindElements(By.XPath("//input[#att='something']")));
if(elementList.Count > 0)
{
//If the count is greater than 0 your element exists.
elementList[0].Click();
}
So I recently figured out another way, which is much faster. If your element has a unique ID or some attribute that exists nowhere else on the page, you can check the PageSource.
driver.PageSource.Contains("UniqueID");
It checks the page to see if the ID or other unique text exists. This happens almost instantaneously, as opposed to using a Try/Catch statement, which takes ~20 seconds. FindElements takes a long time to run too.
I used the accepted answer's solution for some time, but I needed a faster way to check, without waiting for the timeout period every time a check failed. So I made some extension functions that work on IWebElement and IWebDriver that check for the existence of a tag or class.
public static class ExtensionMethods {
public static bool ContainsTag(this IWebElement element, string tagName)
{
string elementText = element.GetAttribute("innerHTML");
return CheckStringForTag(elementText, tagName);
}
public static bool ContainsClass(this IWebElement element, string className)
{
string elementText = element.GetAttribute("innerHTML");
return CheckStringForClass(elementText, className);
}
public static bool ContainsTag(this IWebDriver driver, string tagName)
{
return CheckStringForTag(driver.PageSource, tagName);
}
public static bool ContainsClass(this IWebDriver driver, string className)
{
return CheckStringForClass(driver.PageSource, className);
}
private static bool CheckStringForTag(string text, string tagName)
{
if (!string.IsNullOrWhiteSpace(text))
{
return text.Contains("<" + tagName + ">") || text.Contains("</" + tagName + ">") || text.Contains("<" + tagName + " ");
}
return false;
}
private static bool CheckStringForClass(string text, string className)
{
if (!string.IsNullOrWhiteSpace(text))
{
string pattern = string.Format(".*class[\\s]?=[\\s]?.*[\\s'\"]{0}[\\s'\"].*.*", className);
Match m = Regex.Match(text, className, RegexOptions.IgnoreCase);
return m.Success;
}
return false;
}
public static string InnerHTML(this IWebElement element)
{
return element.GetAttribute("innerHTML");
}
}
Note: This is similar to, but expands on Dominic Giallombardo's answer.
This method will allow you to wait for an element to exist. This is especially important in front end SPA frameworks that conditionally create elements, like Vue.js. You can tweak your retry count based on the performance of your application. In any case, it will wait for your ELEMENT_FIND_WAIT_TIME * ELEMENT_FIND_WAIT_RETRY_COUNT milliseconds before failing completely. This solved the problem we were having.
protected Func<IWebElement> GetLazyElement(By by, int retryCount=0)
{
if (retryCount >= ELEMENT_FIND_WAIT_RETRY_COUNT)
{
throw new Exception("Wait timeout for element to show up" + by.ToString());
}
return new Func<IWebElement>(() => {
try
{
Debug.WriteLine("Finding element " + by.ToString());
var element = _webDriver.FindElement(by);
return element;
}
catch (Exception)
{
Debug.WriteLine($"Failed to find element: {by} (Waiting {ELEMENT_FIND_WAIT_TIME}ms)");
Thread.Sleep(ELEMENT_FIND_WAIT_TIME);
var lazyFunc = GetLazyElement(by, retryCount++);
return lazyFunc();
}
});
}
Dominic Giallombardo's answer worked for me. On Ajax-based information which loads on background, it is a required loop to wait for the element to appear.
So if you want to wait and do an action when the element appear it is possible with a label and a go to label + else condition. Here is the modified code which will wait for the element to appear through a loop:
checksomeelement:
List<IWebElement> elementList = new List<IWebElement>();
elementList.AddRange(driver.FindElements(By.XPath("//div[#class='video']/a")));
if (elementList.Count > 0)
{
elementList[0].Click();
}
else
{
System.Threading.Thread.Sleep(2000);
goto checksomeelement;
}
This is what I use. The "verify" method will return a true or false based on if the element exists. The method named "testfunc" is where you enter the element name. In this example I am looking to see if "English" is displayed on the page.
Also, I notice in the comments in previous posts, people are saying they have to wait 10 seconds or more for the catch to work. Try remove the explicit wait in your code for the catch to work immediately.
static public bool verify(string elementName)
{
try
{
bool isElementDisplayed = driver.FindElement(By.XPath(elementName)).Displayed;
return true;
}
catch
{
return false;
}
return false;
}
static void testfunc()
{
bool test = verify("//option[contains(.,'English')]");
Console.WriteLine(test);
}
If you are using ImplicitWait and want to see if an element is present by using FindElement without waiting, try this code:
ElementExists(By.Id(id));
static public bool ElementExists(By method)
{
var oldTime = _driver.Manage().Timeouts().ImplicitWait;
_driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromMilliseconds(1);
try
{
bool isElementDisplayed = _driver.FindElement(method).Displayed;
_driver.Manage().Timeouts().ImplicitWait = oldTime;
return true;
}
catch
{
_driver.Manage().Timeouts().ImplicitWait = oldTime;
return false;
}
}
I am writing a short program. What I need is that I want to set "correct" parameter in Game.cs, and in my advTry.cs, I want to use this "correct" parameter to determine the output. with my class advTry.cs like:
public bool correct { get; set; }
if (correct)
{
solveButton = new MenuButton(contentManager.Load<Texture2D>("solve"),
buttonCenter, GameState.AnswerNo);
Console.WriteLine("OK");
}
else
{
solveButton2 = new MenuButton(contentManager.Load<Texture2D>("solve"),
buttonCenter, GameState.AnswerYes);
Console.WriteLine("Not OK");
}
While in my GAME.cs, I define correct as:
if (messageString == "18")
{
Console.WriteLine("Main OK");
advTry.correct = true;
}
else
{
advTry.correct = false;
Console.WriteLine("Main not OK");
}
I use the Console.WriteLine to check the passing of boolean parameter "correct". While the result is originally "Not OK", then when I start to input "18", it gives out"Main not OK" first, then "Main OK" (easy to understand, because input"1" then "8").
However, the biggest problem is "OK" never comes out, the state "GameState.AnswerNo" can't be fulfilled, Why is that please? How to fix it please?
Your question is not at all clear. You haven't given any idea of the structure of the code apart from those two conditionals. It's just impossible to answer right now. However, my best guess from what you've written here is that you've set the value of "correct" to true in your advTry class, but you haven't run the code inside that class to output OK to the console. That code won't run automatically just because you set the value of "correct". You need to do something like this in advTry.cs:
private bool _correct;
public bool correct
{
get { return _correct; }
set
{
_correct = value;
output();
}
}
private void output
{
if (_correct)
{
//output "OK"
}
else
{
//output "Not OK"
}
}
I'm using the Windows Event Log to record some events. Events within the Windows Event Log can be assigned a handful of properties. One of which, is an EventID.
Now I want to use the EventId to try and group related errors. I could just pick a number for each call to the logging method I do, but that seems a little tedious.
I want the system to do this automatically. It would choose an eventId that is "unique" to the position in the code where the logging event occurred. Now, there's only 65536 unique event IDs, so there are likely to be collisions but they should be rare enough to make the EventId a useful way to group errors.
One strategy would be to take the hashcode of the stacktrace but that would mean that the first and second calls in the following code would have generate the same event ID.
public void TestLog()
{
LogSomething("Moo");
// Do some stuff and then a 100 lines later..
LogSomething("Moo");
}
I thought of walking up the call stack using the StackFrame class which has a GetFileLineNumber method. The problem with this strategy is that it will only work when built with debug symbols on. I need it to work in production code too.
Does anyone have any ideas?
Here is some code you can use to generate an EventID with the properties I describe in my question:
public static int GenerateEventId()
{
StackTrace trace = new StackTrace();
StringBuilder builder = new StringBuilder();
builder.Append(Environment.StackTrace);
foreach (StackFrame frame in trace.GetFrames())
{
builder.Append(frame.GetILOffset());
builder.Append(",");
}
return builder.ToString().GetHashCode() & 0xFFFF;
}
The frame.GetILOffset() method call gives the position within that particular frame at the time of execution.
I concatenate these offsets with the entire stacktrace to give a unique string for the current position within the program.
Finally, since there are only 65536 unique event IDs I logical AND the hashcode against 0xFFFF to extract least significant 16-bits. This value then becomes the EventId.
The IL offset number is available without debug symbols. Combined with the stack information and hashed, I think that would do the trick.
Here's an article that, in part, covers retrieving the IL offset (for the purpose of logging it for an offline match to PDB files--different problem but I think it'll show you what you need):
http://timstall.dotnetdevelopersjournal.com/getting_file_and_line_numbers_without_deploying_the_pdb_file.htm
Create a hash using the ILOffset of the last but one stack frame instead of the line number (i.e. the stack frame of your TestLog method above).
*Important: This post focuses at solving the root cause of what it appears your problem is instead of providing a solution you specifically asked for. I realize this post is old, but felt it important to contribute. *
My team had a similar issue, and we changed the way we managed our logging which has reduced production support and bug patching times significantly. Pragmatically this works in most enterprise apps my team works on:
Prefix log messages with the "class name"."function name".
For true errors, output the captured Exception to the event logger.
Focus on having clear messages as part of the peer code review as opposed to event id's.
Use a unique event id for each function, just go top to bottom and key them.
when it becomes impractical to code each function a different event ID, each class should just just have a unique one (collisions be damned).
Utilize Event categories to reduce event id reliance when filtering the log
Of course it matters how big your apps are and how sensitive the data is. Most of ours are around 10k to 500k lines of code with minimally sensitive information. It may feel oversimplified, but from a KISS standpoint it pragmatically works.
That being said, using an abstract Event Log class to simplify the process makes it easy to utilize, although cleanup my be unpleasant. For Example:
MyClass.cs (using the wrapper)
class MyClass
{
// hardcoded, but should be from configuration vars
private string AppName = "MyApp";
private string AppVersion = "1.0.0.0";
private string ClassName = "MyClass";
private string LogName = "MyApp Log";
EventLogAdapter oEventLogAdapter;
EventLogEntryType oEventLogEntryType;
public MyClass(){
this.oEventLogAdapter = new EventLogAdapter(
this.AppName
, this.LogName
, this.AppName
, this.AppVersion
, this.ClassName
);
}
private bool MyFunction() {
bool result = false;
this.oEventLogAdapter.SetMethodInformation("MyFunction", 100);
try {
// do stuff
this.oEventLogAdapter.WriteEntry("Something important found out...", EventLogEntryType.Information);
} catch (Exception oException) {
this.oEventLogAdapter.WriteEntry("Error: " + oException.ToString(), EventLogEntryType.Error);
}
return result;
}
}
EventLogAdapter.cs
class EventLogAdapter
{
//vars
private string _EventProgram = "";
private string _EventSource = "";
private string _ProgramName = "";
private string _ProgramVersion = "";
private string _EventClass = "";
private string _EventMethod = "";
private int _EventCode = 1;
private bool _Initialized = false;
private System.Diagnostics.EventLog oEventLog = new EventLog();
// methods
public EventLogAdapter() { }
public EventLogAdapter(
string EventProgram
, string EventSource
, string ProgramName
, string ProgramVersion
, string EventClass
) {
this.SetEventProgram(EventProgram);
this.SetEventSource(EventSource);
this.SetProgramName(ProgramName);
this.SetProgramVersion(ProgramVersion);
this.SetEventClass(EventClass);
this.InitializeEventLog();
}
public void InitializeEventLog() {
try {
if(
!String.IsNullOrEmpty(this._EventSource)
&& !String.IsNullOrEmpty(this._EventProgram)
){
if (!System.Diagnostics.EventLog.SourceExists(this._EventSource)) {
System.Diagnostics.EventLog.CreateEventSource(
this._EventSource
, this._EventProgram
);
}
this.oEventLog.Source = this._EventSource;
this.oEventLog.Log = this._EventProgram;
this._Initialized = true;
}
} catch { }
}
public void WriteEntry(string Message, System.Diagnostics.EventLogEntryType EventEntryType) {
try {
string _message =
"[" + this._ProgramName + " " + this._ProgramVersion + "]"
+ "." + this._EventClass + "." + this._EventMethod + "():\n"
+ Message;
this.oEventLog.WriteEntry(
Message
, EventEntryType
, this._EventCode
);
} catch { }
}
public void SetMethodInformation(
string EventMethod
,int EventCode
) {
this.SetEventMethod(EventMethod);
this.SetEventCode(EventCode);
}
public string GetEventProgram() { return this._EventProgram; }
public string GetEventSource() { return this._EventSource; }
public string GetProgramName() { return this._ProgramName; }
public string GetProgramVersion() { return this._ProgramVersion; }
public string GetEventClass() { return this._EventClass; }
public string GetEventMethod() { return this._EventMethod; }
public int GetEventCode() { return this._EventCode; }
public void SetEventProgram(string EventProgram) { this._EventProgram = EventProgram; }
public void SetEventSource(string EventSource) { this._EventSource = EventSource; }
public void SetProgramName(string ProgramName) { this._ProgramName = ProgramName; }
public void SetProgramVersion(string ProgramVersion) { this._ProgramVersion = ProgramVersion; }
public void SetEventClass(string EventClass) { this._EventClass = EventClass; }
public void SetEventMethod(string EventMethod) { this._EventMethod = EventMethod; }
public void SetEventCode(int EventCode) { this._EventCode = EventCode; }
}
Thanks for the idea of hashing the call stack, I was going to ask that very same question of how to pick an eventId.
I recommend putting a static variable in LogSomething that increments each time it is called.
Now I want to use the EventId to try
and group related errors.
You have filters in event viewer so why (Go to find ? You have 65536 unique event IDs too.
Or rather use log4net or something ??
just my ideas....