Scope issue? Object not recognized in other .cs files of my project
CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 12 of 12

Thread: Scope issue? Object not recognized in other .cs files of my project

Hybrid View

  1. #1
    Join Date
    Oct 2012
    Posts
    4

    Scope issue? Object not recognized in other .cs files of my project

    Dear all,

    I'm new to this forum, and fairly new to C#. So I have a lot to learn, and this one is the first real problem for me. I'm building a tool that is getting information from a GUI, does a number of actions on that data and then gives an output back to that GUI. So far the theory.
    Now for my problem: I create a class in a separate file, instantiate its object in the program.cs file. Then getting data from the GUI I use the form.cs

    I'm using Visual Studio Pro 2010 on Win7 and .NET v4.

    Indicator.cs snippet:
    Code:
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace CompatibilityDeterminator
    {
        class Indicator
        {
            // Accuracy classes according to OIML R76
            internal enum R76_Class {I, II, III, IIII};
            // Load cell interface definition
            internal enum LC_Interface {FOURWIRE, SIXWIRE};
    
            private string       Mfr;               // Manufacturer of the indicator
            private string       Type;              // Indicator type designation
    ...
    ...
           // Properties concerning general information of the indicator
            public string Manufacturer
            {
                get
                {
                    return Mfr;
                }
                set
                {
                    Mfr = value;
                }
            }
    ...
    The program.cs file has the following code:
    Code:
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Windows.Forms;
    
    namespace CompatibilityDeterminator
    {
        static class Program
        {
            /// <summary>
            /// The main entry point for the application.
            /// </summary>
            [STAThread]
            static void Main()
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new Form1());
    
                //Initialize all objects needed in the program
                Indicator IndicatorObj = new Indicator();
                LoadCell LoadCellObj = new LoadCell();
                LoadReceptor LoadReceptorObj = new LoadReceptor();
                Instrument InstrumentObj = new Instrument();
    
            }
        }
    }
    Haven't come any further than this because of my problem
    The form.cs looks like this:
    Code:
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    
    namespace CompatibilityDeterminator
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
    ...
    ...
            private void textBox3_TextChanged(object sender, EventArgs e)
            {
                IndicatorObj.Manufacturer = textBox3.Text;
            }
    ...
    ...
    The IndicatorObj. does not get recognized by VS2010; if I compile it says "The name 'IndicatorObj' does not exist in the current context". I thought that using the namespace mechanism ("namespace CompatibilityDeterminator") would ensure that throughout the project, in all the involved files, the object from the program.cs files would be visible.
    What did I miss? I hope my description of the problem is clear? If not then just let me know.

    Thanks in advance for any help on the matter,
    Martin.

  2. #2
    Join Date
    Jul 2012
    Posts
    90

    Re: Scope issue? Object not recognized in other .cs files of my project

    The Indicator class must be declared public to be visible.

    Code:
    namespace CompatibilityDeterminator
    {
        public class Indicator
        {

  3. #3
    Join Date
    Oct 2012
    Posts
    4

    Re: Scope issue? Object not recognized in other .cs files of my project

    Hi CGKevin,

    Thanks for your quick reply. I tried it, unfortunately it didn't work. I did get some changes; a few internal declared enums caused some troubles during compilation, but declaring them public too fixed that. Then it was back to the above error message again.
    Any more ideas are highly appreciated

  4. #4
    Join Date
    Jul 2012
    Posts
    90

    Re: Scope issue? Object not recognized in other .cs files of my project

    The consideration now becomes the actual scope of the instance of the object. If you are only going to access it in the method, you can create it in the method. If you will need to access it across multiple methods, you'll need to create it at the class level. e.g.

    Here the object is only available inside the method...

    Code:
            private void textBox3_TextChanged(object sender, EventArgs e)
            {
                Indicator IndicatorObj = new Indicator();
                IndicatorObj.Manufacturer = textBox3.Text;
            }
    Here is it available to all methods of the class not just the textBox3_TextChanged method.

    Code:
    namespace CompatibilityDeterminator
    {
        public partial class Form1 : Form
        {
            private Indicator IndicatorObj = new Indicator();
    
            public Form1()
            {
                InitializeComponent();
            }
    ...
    ...
            private void textBox3_TextChanged(object sender, EventArgs e)
            {
                IndicatorObj.Manufacturer = textBox3.Text;
            }
    If you need it to be accessable outside of the class, declare it at class level using the access indicator public instead of private.
    Last edited by CGKevin; October 27th, 2012 at 09:58 AM.

  5. #5
    Join Date
    Jul 2012
    Posts
    90

    Re: Scope issue? Object not recognized in other .cs files of my project

    Ok, now you need to instanciate an instance of your Indicator object like so...

    Code:
    IndicatorObj = new Indicator();
    before you can access it. (
    Code:
    IndicatorObj.Manufacturer = textBox3.Text;
    )

  6. #6
    Join Date
    Jan 2010
    Posts
    1,099

    Re: Scope issue? Object not recognized in other .cs files of my project

    Yeah, what you originally did declares a local variable, with scope defined by Main().
    If you want a globally available instance, which you can get through the Program class interface, then you need to provide a way to obtain it through a static member function or a property (you might also want to implement it using the Singleton pattern).
    However, note that, in general, you should avoid using global object, and distribute data and responsibilities across various classes.
    That said, to make a globally available singleton object, you can do something like this:
    Code:
    namespace CompatibilityDeterminator
    {
        static class Program
        {
            private static Indicator _indicator = null;
            
            public static Indicator Indicator
            {
                get  // get-only property
                {
                    if (_indicator == null)
                        _indicator = new Indicator();
                    
                    return _indicator;
    
                    // Note: this way, only one instance is ever created, 
                    // and the same instance is used everywhere. If this is not desired, you can just use an
                    // auto property, and delete the private member variable; like this:
                    // public static Indicator Indicator {get; set;}   // or
                    // public static Indicator Indicator {get; private set;} 
                }
            }
            
                    
            // Or use a method instead of a property (don't need both):
            public static Indicator GetIndicator() 
            {
                if (_indicator == null)
                    _indicator = new Indicator();
                
                return _indicator;
            }
            
            /// <summary>
            /// The main entry point for the application.
            /// </summary>
            [STAThread]
            static void Main()    // Main() is a static member method
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new Form1());
    
                //Initialize all objects needed in the program
                //Indicator IndicatorObj = new Indicator();   // this declares just a local object
                LoadCell LoadCellObj = new LoadCell();
                LoadReceptor LoadReceptorObj = new LoadReceptor();
                Instrument InstrumentObj = new Instrument();
    
            }
        }
    }
    Then, when you need to access it type:
    Program.Indicator // for the property-based approach
    Program.GetIndicator() // for the method-based approach
    Last edited by TheGreatCthulhu; October 27th, 2012 at 01:51 PM.

  7. #7
    Join Date
    Oct 2012
    Posts
    4

    Re: Scope issue? Object not recognized in other .cs files of my project

    I am experienced in C although it has been some years since I actually coded. So I'm rusty at it to say the least. And my experience in C# and OO is rather limited. So I'm probably looking at it the wrong way.

    I assumed that the namespace mechanism was in some way comparable to the header files in combination with the pre-processor I know from C. And next to that I'm not at all clear on the relationship between the main class and the form class.

    I thought that declaring the different objects in main would give me exactly what I need, but if I read the results right the form class does not run within main, and so they are indeed not recognized in the form class. I actually tried to instantiate the object before the main loop, but that didn't work either.

    And I know I sound like the total newbie I am, but what's a singleton and how does it work?

    I hope my questions and unclarities are making sense to you...

  8. #8
    Join Date
    Jan 2010
    Posts
    1,099

    Re: Scope issue? Object not recognized in other .cs files of my project

    Quote Originally Posted by MartinZ View Post
    I assumed that the namespace mechanism was in some way comparable to the header files in combination with the pre-processor I know from C.
    You mean, something along these lines: http://stackoverflow.com/questions/3...amespaces-in-c

    OK, I'll explain. Namespaces aren't really complicated at all. If you're by any chance familiar with the concept of namespaces as it applies to C++, you should know that namespaces in C# work exactly the same way. But unlike in C, where you have to improvise, in C++, and C# and other such languages they are a language feature.
    The term 'namespace' quite literally describes what they are - they are spaces for names. Think of them as of labeled cardboard storage boxes, into which you can put declarations and definitions of variables, constants, functions, classes, etc.
    You can have a box within a box, within a box... (nested namespaces).

    You want to do this because (1) it enables you to organize your code, and (2) it helps to avoid name conflicts.
    About (2): For example, .NET library comes with a class called Math which provides some static helper math functions, and resides inside the System namespace. If you defined your own Math class for your project, you'd want a way to distinguish it from the one that comes with .NET. The compiler helps in that it will not allow more than one definition of a name inside the same namespace. Normally, you'd define your own namespace ("MyNamespace"), and put your class inside it. Then you can make the distinction in your code by using fully qualified names:

    double cos = System.Math.Cos(angle); // use the math class that comes with .NET Library
    Matrix y = MyNamespace.Math.GetIdentityMatrix(); // use your own class


    The dot (.) operator (member access operator) here acts a lot like a folder separator in file paths. Namespaces are a lot like folders.
    The recommendation is to use the following namespace structure:
    Company.Product.Feature

    For example:CodeGuru.MathTools.Matrix, where Math is the class discussed above.

    To do this in code, you'd write:
    Code:
    namespace CodeGuru
    {
        namespace MathTools
        {
            public class Matrix
            {
                // implementation here
            }
        }
    }
    Or, simply:
    Code:
    namespace CodeGuru.MathTools
    {
        public class Matrix
        {
            // implementation here
        }
    }
    That's rally all there is to it. The using directives you usually see in C# source code simply enable you to avoid extra typing. Building on the last example, without the using directive, you'd have to write
    CodeGuru.MathTools.Matrix.SomeMemberFunction()

    every time you wanted to use the Matrix class.

    If you add this to the top of the file,
    using CodeGuru.MathTools;

    Than you can just write:
    Matrix.SomeMemberFunction();

    Of course, nothing prevents you from typing in the fully qualified name when required (for example, if you're using a 3rd party library that, among other things, also defines a Matrix class). The using directive is valid within the scope of the source file.

    Quote Originally Posted by MartinZ View Post
    And next to that I'm not at all clear on the relationship between the main class and the form class.

    I thought that declaring the different objects in main would give me exactly what I need, but if I read the results right the form class does not run within main, and so they are indeed not recognized in the form class. I actually tried to instantiate the object before the main loop, but that didn't work either.
    OK. I think what's going on here is that you're having problems understanding how scope works when OOP and classes are involved.
    Essentially, all the basic principles are the same. You're familiar with the scope of local variables in C functions (what is called "block scope")? Same thing here.

    In C#, functions can only be defined as member functions of classes (in C++ you can also have free functions). Variables declared within a function body are local, only available for from within that function. Classes define an enclosing scope for their member functions (called methods), and can also declare member variables (called fields). That's what a class is at the core: a custom, user defined type which brings some data and related functions under the same name. Class members have class scope, which means that they are available within the class to every member function. Once you instantiate the class (create an object of the class), member variables live as long as the object lives. However, note that, in the spirit of OOP, classes are normally defined in such a way that only the code from within the class has direct access to it's internal member variables.
    All other code that wishes to use the capabilities of the class must do so through the public member functions of that class. Public members comprise the public interface of the class. All communication happens through the public interface. This provides a high level of control for the class, and helps get rid of a whole family of bugs.

    Now, an analogy: in C, if you want to use a non-local variable within a function, it must either be a parameter, or it must be declared in an enclosing scope (where I include the global scope as an all-encompassing scope).

    Basically, for C# methods, things work the same way. Similarly, if you want to use a non-member artifact from within a class (like a variable from somewhere else), this artifact must either be passed to the class through its public interface, or it must be defined in such a way so that it's globally available.

    In C, when you make a function call from another function, the invoked function doesn't automatically see variables local to the caller.
    Similarly, when in C# you use an object from within some outside function (like Main()), the object's methods don't automatically see the variables declared in the calling function (like Form1 object doesn't automatically see the variables declared in Main()).

    At this point, I should probably explain the static modifier. Normally, members of a class are so called instance members. Basically, as a class defines a type, with data and associated methods, a class is really a blueprint for instances (objects) of that class. An object is an instance of a class in the same way the numbers 2, -12, 256, 12345 are instances of the int type, or in the same way as you, me, CGKevin, or some other individual are all instances of the type "Human".

    As such, each instance of the class has its own copy of the data members defined for that class, and when you perform a method call on an instance, this method will operate on its own copy of the internal data. The members belong to the instances (objects) of a class.

    However, when the static modifier is applied, the member in question becomes shared among all instances of the class. Conceptually, it belongs to the class itself. In a way, in this case, the enclosing class becomes nothing but a namespace for that member (variable or function). If that member is also declared public, it becomes globally available. Any code that can see the class, has access to the static member. Basically, this is how you do global scope in C#.

    Quote Originally Posted by MartinZ View Post
    what's a singleton and how does it work?
    Singleton is one of the design patterns used in OO development. Essentially, it's used for doing global objects the OO way, in case you want only one instance. You can find a lot of info on it on the web, but the gist of it is this. Once you define a class, normally nothing prevents the client code to create as many instances of that class as it likes. Sometimes, what you want is for only one instance to ever be created, and for the same instance to be used throughout the whole program ("singleton" instance). You can accomplish this using the Singleton pattern, by making all the constructors for the class private, and maintaining a single static member variable of the same type as the enclosing class, to hold the only instance. You then provide a public static method (or a property) for client code to use when it wants to obtain that instance. It is implemented essentially the same way I implemented the Indicator property in my code in the previous post, except that it would be done from within the Indicator class itself, with no public constructors. The object is constructed internally once, and then obtain through the static interface of the class.

    P.S. Have you managed to accomplish what you wanted? The suggestion from my last post should work.
    Last edited by TheGreatCthulhu; October 28th, 2012 at 01:09 PM.

  9. #9
    Arjay's Avatar
    Arjay is offline Moderator / MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    10,967

    Re: Scope issue? Object not recognized in other .cs files of my project

    Quote Originally Posted by MartinZ View Post
    The program.cs file has the following code:
    Code:
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Windows.Forms;
    
    namespace CompatibilityDeterminator
    {
        static class Program
        {
            /// <summary>
            /// The main entry point for the application.
            /// </summary>
            [STAThread]
            static void Main()
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new Form1());  // Error: program execution stops here until the main form has been closed.            
    
                //Initialize all objects needed in the program (Note: this initialization doesn't occur until after the form has been closed)
                Indicator IndicatorObj = new Indicator();
                LoadCell LoadCellObj = new LoadCell();
                LoadReceptor LoadReceptorObj = new LoadReceptor();
                Instrument InstrumentObj = new Instrument();
    
            }
        }
    }
    In addition to what the other folks have said, you have a fundamental problem with how your code is organized. See the comments above.

  10. #10
    Join Date
    Jan 2010
    Posts
    1,099

    Re: Scope issue? Object not recognized in other .cs files of my project

    Right - thanks Arjay. The Application.Run() method executes synchronously, and within it runs, under the hood, the windows event loop - so the return point won't be reached until the window is closed. I've been so caught up in explaining the details of the language that I forgot clarify this point (honestly I didn't even pay that much attention to it), and to mention that everything said for the Indicator objects goes for all the other objects that are supposed to be globally available.

    Now, MartinZ, since you said that your experience with OO is limited, I just want to point out once again that often there is a way to avoid using most of the global objects, and use inter-object communication instead - but I won't go into details of that on this occasion.

    If you don't require any special logic regarding getting/setting these global objects, you can use auto-properties (which the compiler will expand into real properties as seen above), like this.

    Code:
    namespace CompatibilityDeterminator
    {
        static class Program
        {
    
            // A static constructor can be used to init static members declared below
            static SimpleClass()
            {
                Indicator = new Indicator();
                LoadCell = new LoadCell();
                LoadReceptor = new LoadReceptor();
                Instrument = new Instrument();
            }
    
    
            // NOTE: With { get; private set; } you will be able to mutate the data members of the currently referenced object, 
            // but client code will not be able to replace it with a new instance of the corresponding class.
            // If you want to be able to replace any of these objects with a different instance
            // from client code, use { get; set; } instead.
    
            public static Indicator Indicator { get; private set; }    
            public static LoadCell LoadCell { get; private set; }
            public static LoadReceptor LoadReceptor { get; private set; }
            public static Instrument Instrument { get; private set; }
    
            
            /// <summary>
            /// The main entry point for the application.
            /// </summary>
            [STAThread]
            static void Main()
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new Form1());
            }
        }
    }
    Note that declarations of class members don't have to come before the place they are used - they have class scope, similar to how labels in C have function scope.

    BTW, if you're confused about what properties exactly are, it's just syntactic sugar for Get/Set method pairs - which is a standard OO way of encapsulating the data in your objects. Instead of allowing direct access to internal variables of a class, OO developers provide a getter and a setter - this way verification / error checking can be done, some additional processing if required, and it helps a lot when debugging if all access goes through one place.

    int GetMyVar() { /* return some internal data */ } // internal data doesn't even have to be of type int!
    void SetMyVar(int value) { /* set some internal data */ }


    Properties are just the result of supporting the idea by a language feature.
    Last edited by TheGreatCthulhu; October 28th, 2012 at 04:02 PM.

  11. #11
    Join Date
    Oct 2012
    Posts
    4

    Re: Scope issue? Object not recognized in other .cs files of my project

    Dear Arjay, thanks for your comments. I actually managed to implement the singleton according to the tips and comments from TheGreatCthulhu (well, I think I did, the compiler stopped complaining )
    Thanks again TheGreatCthulhu for all your help on the matter until now.

    I reversed the order in the Program class so that the initialization takes place before the form gets started. The initialization is still there.
    I must admit though that I was wondering about the use of initialization in the program class (I do an initialization in the forms class as well), but more from the view of operations being done there; I haven't implemented anything yet there and I'm not sure I will.

    I am using (normal?) properties to fill my instance with the required data, so not auto-properties. My guess is that once I get this tool finished and running, and then after time have a look at it, more than a few aspects of the code could have been devised and implemented better. But hey, I gotta start somewhere, right?
    Reminds me of something Les Hatton said when I followed a training on C code quality; how many people do you need to disagree with your code? The answer was one (I got it wrong by the way).
    Anyway as soon as I have the bulk implemented I will try and share the source code with you guys, so you can have look at it (at least I think it's possible to attach files to the thread)

    Thank you again CGKevin, TheGreatCthulhu and Arjay for getting me back on track, your help is greatly appreciated. I hope you'll help with my continuing search through what is turning out to be an interesting language to work with, I already have a few new errors in my code which I'm trying to solve with the help of Google first.

  12. #12
    Arjay's Avatar
    Arjay is offline Moderator / MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    10,967

    Re: Scope issue? Object not recognized in other .cs files of my project

    As part of your learning check out the MVC, MVP, and MV-VM design patterns.

    Also for UI work check out WPF.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  


Azure Activities Information Page

Windows Mobile Development Center


Click Here to Expand Forum to Full Width

This is a CodeGuru survey question.


Featured


HTML5 Development Center