Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Global variable equivalent? (Need object with project-wide scope) 5

Status
Not open for further replies.

jasonp45

Programmer
Aug 23, 2001
212
US
I understand that C-sharp doesn't have global variables, but I'm not quite sure how to do what I need.

I'm building a project in which I want to pass some [optional] command-line parameters to a sub Main, then instance a class I've created (called 'DataFilesHandler') and set properties if parameters were passed.

So far so good - that part has been simple.

Now, however, I want to access that DataFilesHandler class instance in which the properties have been set...but its scope is limited to the Program.cs class in which the sub Main resides; I can't access the object in my form class or any other classes in my project.

What is the correct way to instance this object so I can access methods and properties of my DataFilesHandler instance in the various forms and classes of my project?

Thanks!
 
Can you post the code for the class in question?

[small]----signature below----[/small]
Majority rule don't work in mental institutions

My Crummy Web Page
 
You would normally pass it along to the form via the constructor or some other method.

Christiaan Baes
Belgium

My Blog
 
Code:
//Class: DataFilesHandler
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace GetDataFile
{
    class DataFilesHandler
    {
        public bool PromptForDataNote = false;
        //public byte Category_ID = 0;

        public byte Category_ID
        {
            get
            {
                try
                {
                    switch (Category)
                    {
                        case "A":
                            return 1;
                        case "B":
                            return 2;
                        case "F":
                            return 3;
                        case "S":
                            return 4;
                        default:
                            throw new Exception("Invalid data category detected!");
                            //Throw error
                    }
                }
                catch(Exception ex)
                {
                }
            }
        }

        public string Category
        {
            get
            {
                return category;
            }
            set
            {
                category = value;
            }
        }

        public string State
        {
            get
            {
                return state;
            }
            set
            {
                state = value;
            }
        }
    }
}


//Class: Program
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;

namespace GetDataFile
{
    static class Program
    {
        DataFilesHandler oDFH = new DataFilesHandler();
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        ///<summary>Check for command-line parameters indicating State, DataCategory, and optional DataFile Note. If no parameters present, display form interface.</summary>
        static void Main(string[] args)
        {
            int i = 0;
            foreach (string arg in args)
                i++;
            if (i == 0) //No parameters passed
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new Form1());
            }
            else if (i == 2) //State + DataCategory only
            {
                oDFH.State = args[0].ToUpper;
                oDFH.Category = args[1].ToUpper;
                //MessageBox.Show(oDFH.State + "\n" + Convert.ToString(oDFH.Category_ID));
            }
            else if (i == 3) //Indicates a data-note is to be generated
            {
                oDFH.State = args[0].ToUpper;
                oDFH.Category = args[1].ToUpper;
                oDFH.PromptForDataNote = true;
            }
            else
            {
                throw new Exception("Invalid parameters passed.");
            }
        }
    }
}
 
I think your easiest way to do this will be to pass it in the constructor, as Chrissie suggests. I'm confused though, do you not want to start the form if there are parameters passed?


as an aside, take a look at the "Length" property of arrays. You may find this helpful (rather than doing the foreach to increment i).



[small]----signature below----[/small]
Majority rule don't work in mental institutions

My Crummy Web Page
 
Correct - if parameters are passed I don't want to start the form (the form is only for loading the class properties if they weren't passed on the command-line as parameters). Typically I load this program from the command-line, but sometimes I like to use the form, and the form enables others to use the program without knowing the command-line details.

Thanks, I will pass it to the form's constructor as a parameter as suggested (I think I can figure that out;). And I'll take a look at the 'Length' property; that iteration seemed sloppy but I didn't know how to do it as this is my first C-Sharp project. I'm about halfway through a C-Sharp book but going from a book to actual coding...well the devil's in the details!
 
The "Length" property of an array actually returns the number of items it contains. So int i= args.Length; would do the same thing you're doing already, but more directly and in less code.

Also, in a few chapters you should get to the switch statement, which your example is a perfect candidate for. That would be somethign like this (not tested):

Code:
            switch(args.Length)
            {
                case 0: //no parameters passed
                    Application.EnableVisualStyles();
                    Application.SetCompatibleTextRenderingDefault(false);
                    Application.Run(new Form1());
                    break;
                case 2: //State + DataCategory only
                    oDFH.State = args[0].ToUpper();
                    oDFH.Category = args[1].ToUpper();
                    break;
                case 3: //indicates a data-note is to be generated
                    oDFH.State = args[0].ToUpper;
                    oDFH.Category = args[1].ToUpper;
                    oDFH.PromptForDataNote = true;
                    break;
                default:
                    throw new Exception("Invalid Parameters Passed")
            }

I suggest that you read a bit about this, as you can see its' much cleaner than the if/else if/else if/else mess.

I'm about halfway through a C-Sharp book but going from a book to actual coding...well the devil's in the details!

The fun is in the details too :)

Enjoy!

[small]----signature below----[/small]
Majority rule don't work in mental institutions

My Crummy Web Page
 
Yeah, I implemented a switch statement in the Program class I posted above;).

For some reason the book I'm reading (Murach's C# 2005) discourages the use of switches: "In general, though, most programmers prefer to use if-else statements instead of switch statements because if-else statements aren't as limited." (p 134).

I use Select-Case statements constantly in VB and I prefer them when possible because they seem so much more readable, but I figured maybe C-Sharp programmers tried to avoid them.
 
Hm, that is news to me. Now I am curious as to why it would say that?

I don't use the switch statement all that often, but if I have >3 choices I will use it over a mess of else if's.

I wonder if what it means is you should try to limit the choices to if/else (which as your example shows, is not always possible).

Perhaps someone wiser than me will know the answer.

[small]----signature below----[/small]
Majority rule don't work in mental institutions

My Crummy Web Page
 
i've read about the debate of switch over if/else.
the one which I totally reject is preformance.

Some say if/else is faster than switch. While this may (or may not not) be true to the milli-nano-second. this time isn't going to make a bit of difference for the majority of developers.

if/else is more flexible than switch. so the if logic can be more complex. this reasoning I agree with.
Code:
if( i < 5) return "low";
else if( i > 5 && i < 10) return "medium";
else "high";
Code:
switch(i)
{
   case 1:
   case 2:
   case 3:
   case 4:
      return "low";
   case 5:
   case 6:
   case 7:
   case 8:
   case 9:
      return "medium";
   default:
      return "high";
}

I have found that switch statements require constants while if/else do not.
Code:
if(o.GetType() == typeof(int)) return "is int";
if(o.GetType() == typeof(string)) return "is string";
return "is unknown";

//or

if(o is int) return "is int";
if(o is string) return "is string";
return "is unknown";
Code:
switch(o.GetType())
{
   case "System.Integer":  return "is int";
   case "System.String":  return "is string";
   default: return "is unknown";
}
Code:
//this won't compile
switch(o.GetType())
{
   case typeof(int):  return "is int";
   case typeof(string):  return "is string";
   default: return "is unknown";
}
usually a better option when the condions become very complex is to use the strategy and factory patterns to simplify the client code.
Code:
class Foo
{
   IStrategy Strategy { get; set; }
}

interface IStrategy
{
   string DoSomething();
}

class ThisStrategy : IStrategy
{
   public string DoSomething()
   {
      return int.MinValue.ToString();
   }
}

class ThatStrategy : IStrategy
{
   public string DoSomething()
   {
     return DateTime.Now.ToString();
   }
}

class StrategyFactory
{
   public static IStrategy CreateThat(bool yesOrNo)
   {
      if (yesOrNo) return new ThatStragety();
      return new ThisStragety();
   }
}
Code:
Foo foo = new Foo();

foo.Strategy = StrategyFactory.CreateThat(true);
Console.WriteLine(foo.Strategy.DoSomething());

foo.Strategy = StrategyFactory.CreateThat(false);
Console.WriteLine(foo.Strategy.DoSomething());
this is a very simple example, but it demonstrates how to simplify the logical operations. the strategies themselves are simple and the client (foo) is unaware of the complexities. The logic is contained within the factory. (very simple logic, but it pseudo code:) )

what's really cool about this is when the strategies become more complex you can use ctor args to pass input values thus removing the need for even ulgier logic statements.

here's another example using the interfaces above
Code:
class IntegerStragety : IStrategy
{
   private int number;
   public IntegerStragety(int number)
   {
      this.number = number;
   }

   public string DoSomething()
   {
      return number.ToString();
   }
}

class DateStragety : IStrategy
{
   private DateTime date;
   public DateStragety(DateTime date)
   {
      this.date = date;
   }

   public string DoSomething()
   {
      return date.ToString();
   }
}

public class FactoryInputParameters
{
   private int number;
   private DateTime date;

   public FactoryInputParameters(int number)
      : this (number, DateTime.MinValue);
   {

   }

   public FactoryInputParameters(DateTime date)
      : this (int.MinValue, date);
   {

   }

   public FactoryInputParameters(int number, DateTime date)
   {
      this.number = number;
      this.date = date;
   }

   public int Number { get { return number; } }

   public DateTime date { get { return date; } }
}

class StrategyFactory
{
   public static IStrategy CreateStragetyFrom(FactoryInputParameters input)
   {
      if(input.Number > int.MinValue) return new IntegerStragety(input.Number);
      return new DateStragety(input.Date);
   }
}
then your client code is real straight forward
Code:
FactoryInputParameters input = new FactoryInputParameters(1);
//or
//new FactoryInputParameters(DateTime.Now);
//new FactoryInputParameters(2, DateTime.Now);

Foo foo = new Foo();
foo.Strategy = StrategyFactory.CreateStragetyFrom(input);
Console.WriteLine(foo.Strategy.DoSomething());

Jason Meckley
Programmer
Specialty Bakers, Inc.
 
Jason, that is a fantastic explanation. You covered a lot of the reasons that I very rarely end up using the switch statement (I can't even think of a single one, but I must have used it at some point ;-) ), but didn't think of at the time.

Would it be too bold of me to suggest making it into an FAQ's?

[small]----signature below----[/small]
Majority rule don't work in mental institutions

My Crummy Web Page
 
if you want to go for it. i don't have any reference material to back up my claims. i did think of one final addtion to which would also simlpfy code. a NullStragety object which would be used if no conditions were met.
this would replace throwing an error, or returning null and then required null checks
Code:
class NullStrategy : IStrategy
{
   public string DoSomething()
   {
      return string.Empty;
   }
}
and the factory would be updated to
Code:
class StrategyFactory
{
   public static IStrategy CreateStragetyFrom(FactoryInputParameters input)
   {
      if(input.Number > int.MinValue) return new IntegerStragety(input.Number);
      if (input.DateTime > DateTime.MinValue) return new DateStragety(input.Date);
      return new NullStrategy();
   }
}

Jason Meckley
Programmer
Specialty Bakers, Inc.
 
Part 1: The later part of this thread

After a good long read I have some comments too!

Take a switch statement in use with an Enumeration.

public enum AgeBracket
{
Infant = 1, Child = 2, Adult = 3, Senior = 4
}

You now have a method that is to do something specific based on the age bracket passed in.

public void Entertain(AgeBracket person) { };

Both if and switch are slow because they are go though the logic in sequence rather than performing a search. Let's face it, going through every letter in the alphabet to find out which one the word "Zebra" starts with is slow. To get around this you can use a collection or hashtable.

private Dictionary<AgeBracket, IActionClass>entertainmentObjects = new Dictionary<AgeBracket. IActionClass>();

The IActionClass in this case will be an interface which defines 1 method : PerformAction();

public void Entertain(AgeBracket person)
{
IActionClass entertainer = entertainmentObjects[person];
entertainer.PerformAction();
}

Done.



Part 2: The original issue

I can't access the object in my form class or any other classes in my project

There is no single correct way to design an application. There are methods that work better than others and I'll share with you the one that works for me.

I tend to create a controller. Usually it is a singleton ( because it provides easy access to everything and is not form-dependent. The controller then contains other controllers that are specific to data (Models). Then I have forms that subscribe to those controllers to work with the data. The form doesn't touch the data directly. The form simply asks the controller to perform an action for it with the changes/additions it wants.

This is the basis of the Model View Controller (MVC) design pattern.


I believe that the sooner you get into the habit of using OO concepts and design patterns the quicker you will be able to grow in all modern languages.

 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top