Question

this error has appeared to many of the users, but in my case Visual studio seems to be pointing on a string object. My code is the following:

protected delegate void DPrint_To_LogScreen(string Text, bool NewLine);

protected void Print_To_LogScreen(string Text, bool NewLine)
{
    if (InvokeRequired)
        Invoke(new DPrint_To_LogScreen(Print_To_LogScreen), new object[] { Text, NewLine }); // exception thrown here from the Text string 
    else
    {
        LogScreen.AppendText(Convert.ToString(DateTime.Now) + "  ->  " + Text + (NewLine ? System.Environment.NewLine : ""));
        if (Log_Screen_File == null)
        {
            Log_Screen_File = new StreamWriter(@"Global.log", true);
            Log_Screen_File.WriteLine(Convert.ToString(DateTime.Now) + "  ->  " + Text);
            Log_Screen_File.Close();
        }
        else
        {
            lock (Log_Screen_File)
                Log_Screen_File.WriteLine(Convert.ToString(DateTime.Now) + "  ->  " + Text);
        }
    }
}

I generally want to call function Print_To_LogScreen from different places and threads.

i expected that the "if (Log_Screen_File == null)" statement would do the job (and in the general case it works) but now the exception is thrown by the Text object on the invoke command!!

Is this even possible or Visual Studio means the output file? And if so why the "if (Log_Screen_File == null)" does not work?

thank you

Was it helpful?

Solution

Calling Close does not set it to null. Also, you should be using using here. Change your code to:

    if (Log_Screen_File == null)
    {
        using (Log_Screen_File = new StreamWriter(@"Global.log", true))
        {
            Log_Screen_File.WriteLine(Convert.ToString(DateTime.Now) + "  ->  " + Text);
        }
        Log_Screen_File = null;
    }

That has the same functionality as your code above, except that it won't throw the exception you're currently getting.

It's hard to say what you really want to happen, though. And it looks to me as though you have a potential problem. Imagine that thread A and thread B are executing. Thread A sees that Log_Screen_File == null, and creates it. Then Thread B gets a timeslice and sees that the file exists. Then Thread A gets another timeslice, writes the file and closes it. Thread B will then will try to write to a non-existent file.

If this code will be used by multiple threads, you have to make sure that the entire operation is atomic. I would suggest:

private readonly object logLock = new object();

protected void Print_To_LogScreen(string Text, bool NewLine)
{
    if (InvokeRequired)
        Invoke(new DPrint_To_LogScreen(Print_To_LogScreen), new object[] { Text, NewLine }); // exception thrown here from the Text string 
    else
    {
        lock (logLock)
        {
            LogScreen.AppendText(Convert.ToString(DateTime.Now) + "  ->  " + Text + (NewLine ? System.Environment.NewLine : ""));
            if (Log_Screen_File == null)
            {
                using (Log_Screen_File = new StreamWriter(@"Global.log", true))
                {
                    Log_Screen_File.WriteLine(Convert.ToString(DateTime.Now) + "  ->  " + Text);
                }
                Log_Screen_File = null;
            }
            else
            {
                Log_Screen_File.WriteLine(Convert.ToString(DateTime.Now) + "  ->  " + Text);
            }
        }
    }
}

But do you really want to be opening and closing the file every time? Wouldn't you instead do this:

            if (Log_Screen_File == null)
            {
                Log_Screen_File = new StreamWriter(@"Global.log", true);
            }
            Log_Screen_File.WriteLine(Convert.ToString(DateTime.Now) + "  ->  " + Text);

Assuming, of course, that you close the log file when the program exits.

Come to think of it, you probably don't need the lock at all because that method is executing on the UI thread. The lock doesn't hurt anything, though, and doesn't affect performance.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top