Wrox Programmer Forums
|
BOOK: Professional C# 2008 ISBN: 978-0-470-19137-8
This is the forum to discuss the Wrox book Professional C# 2008 by Christian Nagel, Bill Evjen, Jay Glynn, Morgan Skinner, Karli Watson; ISBN: 9780470191378
Welcome to the p2p.wrox.com Forums.

You are currently viewing the BOOK: Professional C# 2008 ISBN: 978-0-470-19137-8 section of the Wrox Programmer to Programmer discussions. This is a community of software programmers and website developers including Wrox book authors and readers. New member registration was closed in 2019. New posts were shut off and the site was archived into this static format as of October 1, 2020. If you require technical support for a Wrox book please contact http://hub.wiley.com
 
Old October 6th, 2008, 10:58 PM
Registered User
 
Join Date: Oct 2008
Posts: 4
Thanks: 0
Thanked 0 Times in 0 Posts
Default Scope of Objects

I am hobbyist programmer, and although I have a fair amount of programming experience over the years, I am new to object-oriented-programming, and Visual C# in particular. I am trying to write a simple program that will run a high jump competition at a track meet. I have created a class called Competitors that contains all the info for the entrants in the high jump competition. When I instantiate the class, it immediately goes out of scope when an event is fired and the program execution jumps to a new segment of code. How can I instantiate this class in such a way that the object will be available all over the program, particularly in forms other than the one in which it was instantiated? I have tried everything I can think of, including referencing the object all the way back to its namespace root, and I have tried passing the object as an argument when the method is called. More generically, in an event-driven environment like Visual C#, how do you make ANY objects available through the various event methods?
Thanks for any help you can provide.

 
Old October 7th, 2008, 12:37 AM
Friend of Wrox
 
Join Date: Jun 2008
Posts: 1,649
Thanks: 3
Thanked 141 Times in 140 Posts
Default

I'm going to live up to my name on this one and put on my pedantic hat.

First of all, *OBJECTS* don't have scope. They exist in the heap, and the heap is accessible to any part of the same thread and, in many cases, process.

What you are talking about are the *variables* that contain *object references* (pointers, if you are old C person) to the objects.

It's a very important distinction. In C and C++, it *is* possible for an object, per se, to be in scope, because "auto" variables in those languages are on the stack. But not in C#. (And not in Java and not in VB.NET and...but you get the idea.)

Now, all you have to do to make a variable not go out of scope is to move it up "high" enough in your object hierarchy that the object that contains that variable is never destroyed. In ASP.NET, this means that in practice you can move the reference to the page level, since any work done by an ASP.NET page must be done within the purview of the instance of the page object that is currently processing the user's HTTP Request. (And if you are building a standalone C# executable, then all that I said about the ASP.NET page simply applies to the object that contains the main method that was started by execution of your program.)

This might, of course, be too high for your liking. But that's okay, now you just have to make sure that your variable is within some object to which a reference is retained by the page object. Or one that is referenced by an object that is referenced by... Well, you get the idea. The chain of "live" objects can be as long as need be, and so long as they are all "live" then your object, referenced by any one of them, will stay "live", too.

Now, being "live" is of course not the same thing as being "in scope." Scope has to do with "visibility", not "viability."

And here we get to the point where it's hard for me to advise you. You say your object "goes out of scope when an event is fired." Well, that means that, at a minimum, the reference to your Competitors class must be held by the object that the event was fired on (if not by some object higher in the "tree" of objects). But since I don't know what other classes are in your code, and what their relationship to each other is, I really can't say much more.

You'll need to show the layout of your classes (e.g, an E-R diagram or equivalent) for us to really understand your situation.
 
Old October 8th, 2008, 07:25 PM
Registered User
 
Join Date: Oct 2008
Posts: 4
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Thank you very much for your help!

Unfortunately, I am still confused. I am just making out Windows Forms Application, not an ASP.NET application. ASP.NET applications are not addressed until later in this book. I realize that object references are just pointers, but as I understand the rules in C#, that reference is only available within the curly brackets within which it was created. I would think that it would be allowed to instantiate an object within the "Main" segment (the starting point) of the application, and then it would be available throughout the whole application. However, that is not the case, because I've tried it and it does not work. Please don't misinterpret what I say to imply that I think the language should be changed; rather, I am just trying to understand the rules of how the language works. Computer languages are logical structures, but I can't seem to grasp of the concept of how (or where) to instantiate an object to make it available to other segments of the application.

Prior to your response, I was not even aware of what an E-R Diagram was! I have now looked it up on Wikipedia, and I see that it is a very useful concept, but I need to do a little more research on that before I could actually develop one. I don't really know any other way that I could give you a "layout of [my] classes" - can you give me any other suggestion?

Thank you again for your help. It is greatly appreciated. I just work on this stuff to educate myself, and you have certainly helped educate me with your response.

 
Old October 8th, 2008, 09:31 PM
Friend of Wrox
 
Join Date: Jun 2008
Posts: 1,649
Thanks: 3
Thanked 141 Times in 140 Posts
Default

No, there is nothing special about main. Same rules: If you define the variable within the {...} that describe the code for the method, the variable is invisible outside the method.

That is:
Code:
public class Demo
{
    public static void Main( )
    {
        String foo = "bar";
        Zamboni( );
    }
    public static void Zamboni( )
    {
        print(foo); // ERROR!  no such variable
    }
}
You *will* get an error. foo is local to only the Main method.

But what I said in all that mess of mine holds: You have to move the *declaration* of that variable higher in the hierarchy.

So...
Code:
public class Demo
{
    private String foo = "mixolydian";

    public static void Main( )
    {
        foo = "bar";
        Zamboni( );
    }
    public static void Zamboni( )
    {
        print(foo); // and now it works!
    }
}
Do you see it? The foo variable now is in scope for BOTH methods. Note that if you were to run this program, *as is*, you would see the string "bar" printed.

Notice also that although foo is in scope for both methods here, if you had *another* class, it would NOT be able to see foo.

That is if you code:
Code:
public class Another
{
    public static show( )
    {
        print( Demo.foo );  // error: foo is inaccessible from outside  Demo class
    }
}
you will get the error noted. But if you changed
    private String foo
to
    public String foo
the code would work! And, depending on whether the Main method in class Demo had been called or not, its value might still be "mixolydian" (or not).

I'm more than a little surprised that you haven't learned this from whatever source material you are using. I would probably recommend that you consider switching to another book or tutorial or whatever. I really thought you were asking a "deeper" question, hence my somewhat irrelevant spewing. Sorry.
 
Old October 9th, 2008, 04:16 PM
Friend of Wrox
 
Join Date: Sep 2008
Posts: 234
Thanks: 0
Thanked 32 Times in 30 Posts
Default

Old Pedant raises some important issues relative to your question. The key is understanding the difference between value types and reference types. Value types, like an int, are variables whose memory address holds the data you're interested in. Reference types can only hold two values: null, or a memory address where the data you need are stored. Fully understanding this isn't easy, but is necessary to fully understand scope.

I also think the statement that scope and lifetime are not related can be misleading. If you define a variable within a method, it has local scope and its life ends when control leaves that method. A data structure defined within a class has class scope and exists as long as the class object exists.

There is also a serious difference between the terms "define" and "declare" yet most programmers treat them as being the same. They are not. You need to understand the difference to full understand the answer to your question. (See: http://www.ddj.com/cpp/208808373?cid=RSSfeed_DDJ_All) I use the Bucket Analogy in my book to explain this if the DDJ article doesn't help. Old Pedant's suggestion of a different book might be helpful and of course I hope you'll consider mine. Please read the reviews on Amazon to see if it might be helpful. (http://www.amazon.com/Beginning-3-0-...1571215&sr=8-1)

Dr. Purdum


Jack Purdum, Ph.D.
Author: Beginning C# 3.0: Introduction to Object Oriented Programming (and 14 other programming texts)
 
Old October 9th, 2008, 05:11 PM
Friend of Wrox
 
Join Date: Jun 2008
Posts: 1,649
Thanks: 3
Thanked 141 Times in 140 Posts
Default

> I also think the statement that scope and lifetime are not related can be misleading.

Yes. If you read that into one of my answers, mea culpa.

And yet it is also true that scope and lifetime *for a particular instance variable* may not be in sync. That's because there could be multiple variables each referencing the same object, and the fact that one variable goes "out of scope" is not sufficient to "kill" the object instance.

So, again, I echo Dr. Purdum: "Fully understanding this isn't easy, but is necessary ..."

I haven't yet gotten Dr. Purdum's book, but just based on his answers here and on reviews I have seen, I've recommended it to a couple of people, already. You surely couldn't lose by buying it, I believe.
 
Old October 10th, 2008, 03:51 PM
Friend of Wrox
 
Join Date: Sep 2008
Posts: 234
Thanks: 0
Thanked 32 Times in 30 Posts
Default

Thanks for the kind words, O.P. I think we both know that one of the hardest things for students to understand is the whole idea of what a reference variable really is and how it is used. And when you tell them that you can have two variables reference the same data, you can actually see their eyes glaze over!

Handman: The good news is, that once you've mastered reference variables, you'll be amazed how much more efficient your coding style becomes! It's worth the effort to fully understand what's "under the hood" for reference variables.



Jack Purdum, Ph.D.
Author: Beginning C# 3.0: Introduction to Object Oriented Programming (and 14 other programming texts)
 
Old October 11th, 2008, 06:38 PM
Registered User
 
Join Date: Oct 2008
Posts: 4
Thanks: 0
Thanked 0 Times in 0 Posts
Default

I am EXTREMELY grateful to both Old Pedant an DrPurdum for your continued interest in helping me with my problem. I'm hoping you won't get frustrated with me when I tell you I am still having problems.

When I first expressed my problem, I was probably a bit vague in my explanation. I believe I understand the concepts of declaring and defining a variable, as well as the concept of a pointer to a variable and the value it contains. I had those concepts beat into my head years ago when I learned IBM 360 Assembly Language (yes, I am older than I look!)

It's the practical side of this issue that is causing my problems. Old Pedant, you wisely tell me that I need to move my object instantiation to a higher level in the hierarchy, but I can't figure out where to instantiate the object to make it usable in two different forms. Where is "higher in the hierarchy" in that situation?

Getting back to the example you gave in your last post, say you have defined a Windows Form called Form1 which will exist in the file Form1.cs, and within that file you instantiate Class Demo:

    Demo MyObject = new Demo;

Then you do some things with MyObject within Form1, but later you need to go to Form2 with the following code:

    Form2 MySecondForm = new Form2;
    MySecondForm.Show();

Finally, you try to access MyObject from within Form2:

    MyObject.Zamboni();

An exception will result: "The name 'MyObject' does not exist in the current context".
The file Form1.cs and Form2.cs have two distinct, non-overlapping sets of {}, and I don't see any place to instantiate MyObject that will span both of those files. Even the following reference to MyObject raises an exception:

    Form1.MyObject.Zamboni(); // Exception: Form1.MyObject is inaccessible due to its protection level (despite the fact that I have declared all entities public).

So what do I do now?

Thank you again for your patience and your help! (Please don't tell me I need to go back to Visual Basic - I'm trying to move beyond VB! :))


 
Old October 11th, 2008, 10:23 PM
Friend of Wrox
 
Join Date: Jun 2008
Posts: 1,649
Thanks: 3
Thanked 141 Times in 140 Posts
Default

Ah, well...this is worse than you think!

First of all, let's clear up the difference between DECLARE and INSTANTIATE and DEFINE.

You DECLARE a variable that *may or may not* reference an object of the type it is declared as.
     Foo f = null; // f is declared as a reference to an object of type Foo
You INSTANTIATE an object by using the new operator:
     new Foo( ); // an object is created!
And you DEFINE a value for the already-declared variable f by assigning that instantiated object to the variable, as in:
     f = new Foo( );
Finally, you *can* do all 3 of these *separate and distinct actions* in one statement in C# (and in most languages, but not all). In C#, you simply do
     Foo f = new Foo( );

Okay?

Now to your problem...

When you run the code from Form1.cs, you instantiate an instance of the Form1 object.

When you run the code from Form2.cs, your instantiate an instance of the Form2 object.

BUT WHERE IS THE *REFERENCE* to each of those FORM objects????

If there isn't any "outer" object that has a variable that references each of the objects, then THOSE OBJECTS DON'T EXIST when their execution is finished!

So no matter WHAT the scope of any variable, no matter how the objects referenced by those variable were created, neither the Form *NOR THOSE OBJECTS* still exists when the execution completes.

Now, I need to tell you that I am *NOT* a Windows Forms programmer, at all. ASP.NET, yes. Java, both in JSP and in standalone, yes. So here we get into the range of speculation.

I am *assuming* that in a Windows Forms application, there is some outer control module (instance of a control class, one assumes) the is executed when you run "myWinFormProgram.exe".

And almost surely it is that "control module" that is responsible for moving the user from one form to another. Meaning it instantiates a Form1 object or a Form2 object, as needed.

And that means the ONE way you can communicate between Form1 and Form2 is to use an object reference that is independent of either of them. An object reference in the "control module." In short, a reference that is "higher in the hierarchy."

BUT...

Experimentation is a wonderful thing.

THERE IS ANOTHER WAY TO DO THIS.

As I said, I'm not a Windows Forms person, but I happen to have VS 2003 here, so I tried using it to create a WinForms project in C#.

And it occurred to me that in any form based project, you are going to have one "master form" that controls all the other forms. And naturally, this would normally be the first form created, the "Form1.cs" that you get by default.

So if Form1 is used to invoke Form2, by doing something like
     Form2 f2 = new Form2( );
then that means that Form1 will *always* be "alive" (still in memory) when the code in Form2.cs is executing.

Okay, so just make the desired members of Form1 public!!!

I did this by dragging a textbox and a button onto Form1. Then I changed the declaration of the textbox from
    private System.Windows.Forms.TextBox textBox1;
to
    public System.Windows.Forms.TextBox textBox1;

And then I also dragged a textbox onto Form2 and then changed the contructor for Form2 to this:
Code:
    private Form1 f1 = null; // added this, too
    public Form2(Form1 f)
    {
        InitializeComponent();
        f1 = f;
        // And this next line could be here *OR* it could be
        // any place in the rest of the code for Form2!
        // It simply copies from Form1's text box to Form2's text box.
        textBox1.Text = f1.textBox1.Text; 
    }
And, finally, I used this code for the button click in Form1:
Code:
    private void button1_Click(object sender, System.EventArgs e)
    {
        Form2 f2 = new Form2(this);
    }
And VOILA! When the button is clicked, a new Form2 object is created, and the text from button1 in the Form1 object is copied--BECAUSE IT IS NOW PUBLIC it can be!--to the text box in the Form2 object.

[Okay, what I don't know how to do is to then cause the Form1 display to disappear and have the Form2 display then appear in its place. Like I said, not a Windows Forms person.]

But the point is, by passing a reference "to myself" (the this in the button1_Click method) to Form2 when it is created, all public members of myself (Form1) are now accessible to Form2 by way of that passed reference (that I stored in a reference variable in Form2).

PHEW! Does all that make sense???

There may be better ways to pass around object references in a windows form app. I notice that all the forms are in the same namespace (namespace WindowsApplication1, by default), so you could also have an independent class that holds all your public data. You'd instantiate that in the starting form and pass a reference to it to all your other forms and/or utility code.

Anyway, I guess my experimentation showed me that, by default, a C# WinForm project really *does* have the initial instantiation of Form1.cs (or whatever you rename it to) as the top level object in the executable code. Which does simplify some things. (E.g., you can put all the stuff you want to share amongst all other forms in Form1.cs as public members, so long as you then pass a reference to Form1 to the other objects.)

At this point in time, I'll pass the buck to Dr. Purdum, but I'd bet that he suggests that you go buy his book. As you should.
 
Old October 11th, 2008, 10:41 PM
Friend of Wrox
 
Join Date: Jun 2008
Posts: 1,649
Thanks: 3
Thanked 141 Times in 140 Posts
Default

AHA! Figured it out!!!!
Code:
    private void button1_Click(object sender, System.EventArgs e)
    {
        Form2 f2 = new Form2(this);
        f2.ShowDialog(); // this shows form2!!!
    }
And I also realized that the only reason Form1 is the "top level object" is because it contains (by default) the
     static void Main()
method. You *could* create an Uber-Object that would get that Main() method, instead, and use it to drive all the forms, etc., etc. And that would probably be the logical place to then put all the info you want to share among the various forms. As I did for Form2, you need to modify the constructors of each form (or whatever) to take a reference to the Uber-Object so that they can, indeed, get to those public members.

WHEW!

Hey, I almost understand Windows Forms!!!

[And I'm not older than I "look". I'm exactly as old as you'd expect an "Old Pedant" to be. <grin/>]





Similar Threads
Thread Thread Starter Forum Replies Last Post
Static Scope JaneDean Beginning PHP 0 November 25th, 2008 02:07 AM
Scope Issue iceman90289 C# 2005 8 April 5th, 2008 03:41 PM
"Out of scope" var??? yankleber XSLT 2 March 31st, 2007 03:53 AM
scope problem jc Javascript 0 July 29th, 2003 09:27 AM





Powered by vBulletin®
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
Copyright (c) 2020 John Wiley & Sons, Inc.