2

I have a Windows Forms Application with a global variable - a string called testPath.

This string is used to save a path - by default it is C:\temp\. When the user clicks a button, this directory is created (if it does not exist already).

There is also a textbox control, in case the user wants to change the value of the path.

At the button's event handler, I try to access testPath and I get a null reference.

I am not changing the value of testPath anywhere, except when I pass it to and from the textbox Control.

What am I doing wrong? How does the global variable have something inside at one second, and then right afterwards it points to a null reference?

Here is the complete code:

public string testPath = @"C:\temp\";

public MainForm()
{
     //Windows Designer call
     InitializeComponent();

     //Show the testPath in the textBox (using Invokes)
     this.textBox1.Invoke(new MethodInvoker(delegate { this.textBox1.Text = testPath; } ));

     //here, testPath contains 'C:\temp\'
}

//Button "Click" handler
private void Button1Click(object sender, EventArgs e)
{
     //here, testPath contains a null reference!

     //If the user changed testPath in the textBox, we need to save it again
     this.textBox1.Invoke(new MethodInvoker(delegate { testPath = this.textBox1.Text; } ));

     //Create the path
     if(!Directory.Exists(testPath)) //If it does not exist already
     {
         Directory.CreateDirectory(testPath); 
     }

     //...Do something else

}
PDoria
  • 552
  • 2
  • 11
  • 25
  • 3
    There are no global variables in C#. A member variable, maybe? – GregC Jun 14 '12 at 16:43
  • I'm assuming this code is all in one file and inside the same namespace. If that's the case, you must have code elsewhere in that file which is causes testPath to be set to null. Double check that.. – Robert Levy Jun 14 '12 at 16:45
  • Can you show your complete class? If that's too long, possibly the "complete" class while omitting the members that are not referenced here? – O. R. Mapper Jun 14 '12 at 16:45
  • I used what you gave us and it worked fine. When I got to the button click, testPath still contained it's value. There has to be some other piece of code breaking this. Also, unless this is being accessed from outside this form, you should make it private. If it's being accessed, you should make it a property. – Yatrix Jun 14 '12 at 16:54
  • I did not expect so many responses. I shall update the first post with more info. Thanks – PDoria Jun 14 '12 at 16:59
  • @user1183352 then you have underestimated the SO community! How daaaare you! – Yatrix Jun 14 '12 at 17:01
  • The code works as expected for me. – Security Hound Jun 14 '12 at 17:59

4 Answers4

8

I would suggest making this a constant:

const string testPath = @"C:\temp\";

This will cause any attempt to set the value to be flagged as a compiler error. Using the value will work without changes.


Edit in response to comments:

Since you want to change the value, I would recommend reworking this as a property:

private string _testPath = @"C:\temp\";
private string testPath 
{ 
    get { return _testPath; }
    set
    {
        _testPath = value;
    }
}

You can then set a breakpoint on the line _testPath = value;, and see, in the debugger, exactly what is setting this to null. Once this is corrected, I would then recommend fixing the naming to match standard .NET naming conventions.

Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
  • I'd still like to know why his isn't working. I made a form with a button and copied his variable and button click code and mine worked fine. – Yatrix Jun 14 '12 at 16:52
  • 2
    @Yatrix Yeah - something else, somewhere, is setting it. By making it `const`, the original poster will be able to see exactly what is causing it to be set to null, since it'd be a compiler error. – Reed Copsey Jun 14 '12 at 16:54
  • Thanks for the response, but I did not mention that I also have a textbox control in the App. This is used in case the user wants to modify testPath. At the start, the textbox shows what is inside testPath. Then, when the button is clicked, the textbox's text is copied back to testPath in case the user modified it - and the path is created. In this context, setting the variable as a constant would not help me since I need to change its value. – PDoria Jun 14 '12 at 17:06
  • Good idea. I'll do this immediatly and let you know what comes up. – PDoria Jun 14 '12 at 17:10
  • I've done this, and the problem remains. BUT, in the line that I set _testPath = value, I can see the correct path inside both ('_testPath' and 'value'). On all other references to testPath however, I get nothing but null references (I use the IDE's console to check the variable's contents in different breakpoints). I understand the convention of using gets and sets - how this kind of encapsulation is safer. What I don't understand is why there are null references outside the get / set lines. – PDoria Jun 14 '12 at 17:20
  • @user1183352 Are you sure you're in the same instance? Did you check "value" when you were in the breakpoint (not _testPath)? – Reed Copsey Jun 14 '12 at 17:22
  • The value of "value" and "_testPath" in all other breakpoints (other than the one in '_testPath = value;') always points to a null reference as usual. Like all basic Windows Forms Projects, I have a Program.cs and a MainForm.cs. The Form is, of course, inside MainForm.cs (as well as testPath)... So testPath should be in the same thread as MainForm. – PDoria Jun 14 '12 at 17:27
  • @user1183352 I recommend editing your post to show the entire code for MainForm.cs - at least all routines that use testPath or _testPath – Reed Copsey Jun 14 '12 at 17:32
  • There are other methods that use testPath (and _testPath) but only AFTER the Directory is created... And I am not using any threads apart from the main which the program is running on. Why is it that up until the CreateDirectory() line I can't access the value inside testPath? There are only two things that I can think of - First, the IDE that I'm using might be doing something wrong in memory. Second, I read that it is safer to use Invokes rather than changing the TextBox.Text property directly (because of GUI-related threading issues). – PDoria Jun 15 '12 at 08:52
  • 1
    @user1183352 Without showing your code, there is *no way for us to help* – Reed Copsey Jun 15 '12 at 16:40
3

I would try marking the field testPath as readonly, and follow the compiler errors.

Here's a tutorial on differences between const and readonly.

EDIT You could look at implementing a custom handler for the form load event and inspect the state there. You could also use step through using F10 as you're constructing the object, as you're handling form load event, and as you're handling user input. Keep in mind that when just entering the function, all variables show as uninitialized on the opening curly brace. You'd have to step through the function at least once to see them. Use a pin to keep an eye on your variables in the text editor.

GregC
  • 7,737
  • 2
  • 53
  • 67
  • http://stackoverflow.com/questions/55984/what-is-the-difference-between-const-and-readonly – GregC Jun 14 '12 at 16:51
  • Considering that I would like to change the value of testPath, I would really prefer not to set them as constants or read-only... Thanks for the idea though. – PDoria Jun 14 '12 at 17:07
  • He didn't mean to make it readonly in a permanent way, but just as a debugging tool to see where it is set to null – Francesco Baruchelli Jun 15 '12 at 07:31
  • I just changed testPath to readonly, and I have the same problem. I have two breakpoints immediatly before and after the Form's Constructor - Before the Form loads, testPath is OK. Right after it loads, I get a null reference. And I get no compiler errors, warnings or exceptions when I run the code. This is much more confusing especially because of that. – PDoria Jun 15 '12 at 08:59
  • I've overriden the Form's Load event and placed a "string test = testPath" in there. As usual, testPath contains the right value just as the form loads, and points to a null reference when debugging the button click event handler. Also, I'm using breakpoints and the IDE's console to monitor the contents of testPath. – PDoria Jun 15 '12 at 16:42
  • @user1183352 I am in agreement with Reed Copsey. I don't see a way forward without complete code to repro. – GregC Jun 15 '12 at 17:15
1

Updated: I am not sure why do you need this public variable. If you simply want to initialize the control with some initial value like "C:\temp\" & user can edit it if he wants. If that is the case, open the form in design view, right click on textbox > go to properties. In properties window, change the Text property to "C:\temp\", after you are done with this, your text box will be initialized with "C:\temp\". In event handler you can simply write

private void button1_Click(object sender, EventArgs e)
{
     if (!Directory.Exists(this.textBox1.Text.Trim()))
        {
            Directory.CreateDirectory(this.textBox1.Text.Trim());
        }

}

Original: testPath variable is getting modified to null after the Form is initialized but before the button is clicked. Since, it is a public variable, it can be accessed & modified from outside the class as well.

One easy way to reproduce this issue - In Program class > Main method

[STAThread]
static void Main()
{
   Form1 obj = new Form1();
   obj.testPath = null;
   Application.Run(obj);
}

Suggestions: 1. Make testPath constant or read-only to determine if it is being modified. 2. Change access specifier to private if you do not need to expose it.

  • It really does seem like something is modifying testPath (apart from my code). Also, testPath was private at the start - I changed to public in hopes that increasing its visibility would fix the problem. However, like I've pointed out in other posts, I need to modify testPath so setting it to a constant or read-only type would really not help my situation. Thanks though – PDoria Jun 14 '12 at 17:24
  • I tried changing the Text property in Designer mode, but I get the same problem - The "Text" property of the TextBox is not visible or set to a null reference along the code. – PDoria Jun 15 '12 at 08:47
0

I would suggest that instead of declaring the path outside the scope of your button click event, you declare it inside the method.

Like so:

private void Button1Click(object sender, EventArgs e) 
{ 
     string testPath = @"C:\temp\"; 

     //Create the path if it does not exist      
     if(!Directory.Exists(testPath))      
          Directory.CreateDirectory(testPath);       
}
Yatrix
  • 13,361
  • 16
  • 48
  • 78
Brian
  • 1