Keep my list/dictionary as globally accessible - c#

Ok... I'm trying to understand this whole object oriented programming but I keep ending up in a dead end. ;)
I'm trying to store or rather will store a great deal of data with using classes as I should. I want to store planetary data by using a class with several properties, I will then save these into a list.
My problem is that I don't know how to make this list globally accessible, it is only accessible in the instance where it is created.
Some sample code from my test environment below.
OrbitalBodies.cs
class OrbitalBodies
{
public int BodyID { get; set; }
public string BodyName { get; set; }
public int BodySize { get; set; }
public int BodyX { get; set; }
public int BodyY { get; set; }
}
From1.cs
public void button1_Click(object sender, EventArgs e)
{
var bodies0 = new OrbitalBodies();
var orbitalList = new List<OrbitalBodies>();
bodies0.BodyID = 4;
bodies0.BodyName = "Earth";
bodies0.BodySize = 125;
bodies0.BodyX = -450;
bodies0.BodyY = 75;
orbitalList.Add(bodies0);
bodies0.BodyID = 0;
bodies0.BodyName = "Sol";
bodies0.BodySize = 500;
bodies0.BodyX = 0;
bodies0.BodyY = 0;
orbitalList.Add(bodies0);
//var orbitalDic = new Dictionary<int, OrbitalBodies>();
MessageBox.Show("Planetary body name: " + Convert.ToString(orbitalList.Count()));
}
I have spent a couple of hours looking up my problem here and other places but I don't know how I can access the information I put into the list other than in that single instance. My real application will have tens of thousands of orbital bodies and many other data that must be accessible throughout many forms and perhaps even other classes.
Some help would be appreciated, what is the best solution? Do it completely differently?!?

You don't want static members or singletons (both of which cause more problems than they solve), you need Dependency Injection.
Outside of your form create the List, pass it into the forms constructor. Everywhere you need to use the list, pass the instance you have from the form.
This way there is only one list, everywhere that needs the list is passed a list (that just happens to be the same list).
If in time you realize you actually need to model two different systems, you just create two different lists, and pass them to two different forms, everything keeps working and you don't need to go back through your code removing references to static members.
Honestly, this is completely doable without going to the dark side and perpetuating the evil that is static/global variables.
NB Why static variables are considered evil

Use design pattern Singleton.
public class Globals
{
private List<OrbitalBodies>() orbiralList;
private static Globals instance;
private Globals()
{
this.orbiralList = new List<OrbitalBodies>();
this.instance = NULL;
}
public static List<OrbitalBodies>() GetOrbitalBodies()
{
if (instance == null) instance = new Globals();
return instance.orbitaList;
}
}
Then everywhere in your code, when you will need orbitalList call
Globals.GetOrbitalBodies().<do whatever with your list>
Try not to use static classes, because they are mess in term of OO design.

Make OrbitalList a property:
public List<OrbitalBodies> OrbitalList {get;set;}
public void button1_Click(object sender, EventArgs e)
{
var bodies0 = new OrbitalBodies();
bodies0.BodyID = 4;
bodies0.BodyName = "Earth";
bodies0.BodySize = 125;
bodies0.BodyX = -450;
bodies0.BodyY = 75;
OrbitalList.Add(bodies0);
//...
}
//Then you can do:
doSomething(myForm.OrbitalList[0]);

If you just want to access your list within the "Form1" class, just declare it as a private member out of a function:
private List<OrbitalBodies> _orbitalList;
and then instanciate it into your "button1_Click" method.
If you want to access your list in all your classes, I suggest you make it static :
public class NewClass
{
public static List<OrbitalBodies> OrbitalList {get; set;};
}
and you call it like this
NewClass.OrbitalList;
Hope that helps.

Related

Running the same method for different variables in a class

I have a class with about 10 or more different boolean values that record whether a user has done a particular action that will give them a specific reward (e.g. send a message to someone).
here is the code for one method for ONE bool/action:
private ReqRewardResult setMsgSent(RewardClass reward, RewardInfo info)
{
if (reward.msgSent)
return ReqRewardResult.RewardAlreadyGiven;
reward.msgSent = true;
reward.earned += info.msgSentReward;
return ReqRewardResult.ReqSuccess;
}
I have tried to create a generic method for this but it seems you can't pass a class variable as a reference?
private ReqRewardResult setRewardAction(ref bool bAction, RewardClass reward, int reward)
{
if (bAction)
return ReqRewardResult.RewardAlreadyGiven;
bAction = true;
reward.earnedTokens += reward;
return ReqRewardResult.ReqSuccess;
}
I have then looked at a couple of methods such as using a delegate function... but this is then kinda pointless as i'd have to repeat several lines again...
I have also seen you could use Reflection... but this is really slow and as this is a web app i'd rather use more repeated code if it improves the overall speed...
The question: Is there anyway to have a class function that can repeat for several variables of the same type without any performance hit?
NOTE: This class is data that is loaded from a database and is unique to each user (there could be millions of users)
Many Thanks,
Phil.
class RewardCredit
{
public bool Rewarded { get; set; }
public int Points { get; set; }
}
You could use a Dictionary<string, RewardCredit>, fill it with reward names as strings and have a function like
void ApplyReward(string rewardName)
{
if (!rewards.ContainsKey(rewardName))
{
return;
}
RewardCredit credit = rewards[rewardName];
if (!credit.Rewarded)
{
tokens += credit.Points;
credit.Rewarded = true;
}
}
You'd then end up using it like so
Dictionary<string, RewardCredit> rewards = new Dictionary<string, RewardCredit>
{
{ "Message", new RewardCredit { Points = 10 } },
};
ApplyReward("Message");
First it looks like you have a finish and known set of possible user actions that can be rewarded with "tokens" if done by a user.
This can be implemented with the following class:
public sealed class UserAction
{
public static UserAction SendMessage = new UserAction(3);
public static UserAction PhonedFriend = new UserAction(4);
public static UserAction LikedPost = new UserAction(1);
public static UserAction CommentedOnPost = new UserAction(2);
private UserAction(int tokens) => Tokens = tokens;
public int Tokens { get; }
}
Notes:
The constructor is made private and only the few instances of this class that must exist are available with predefined names and tokens
The class is sealed to avoid being inherited, so that it effectively is impossible to create other instances than the one you provided
Then, so far I understand, each user may have done each action (or not) but must be rewarded no more than once for each. This make me think that you need to store a set of these UserActions into a User. You also need a way to add an action to a user (when he effectively does in on the UI, for example) and also be able to know how much tokens each user has earned. The following class implements such behavior:
public sealed class User
{
private readonly HashSet<UserAction> _doneActions;
public User() => _doneActions = new HashSet<UserAction>();
public ReqRewardResult AddAction(UserAction action) => _doneActions.Add(action) ? ReqRewardResult.ReqSuccess : ReqRewardResult.RewardAlreadyGiven;
public int EarnedTokens => _doneActions.Sum(ua => ua.Tokens);
}
Note:
I'm taking advantage of the HashSet.Add()'s return value to determine if the action had already been done in the past or not
Advantages of this "object-thinky" solution:
No more booleans and if, which I believe makes your code more maintainable and clear
Simplicity to add a new UserAction (one LoC)

Inheritance-Need Guidance

I am a novice programmer, so sorry if this is a really stupid question. I need to pass a value from one class to another. If I am not mistaken, this would be done through inheritance, but there seems to be something I am missing. Any help would be welcome. I am writing in C# within Unity.
public class baseStats{
private int STAMINA;
public static int Stamina{
get{return STAMINA;}
set{STAMINA = value;}
}
}
The above is a sample of my parent class. Here is my child class:
public class Profile : baseStats {
private static int PROFILE_STAMINA;
private void Stats ()
{
PROFILE_STAMINA = Stamina;
}
public static int profileStamina
{
get{return PROFILE_STAMINA;}
}
}
In a third script I created for the purposes of debugging, I wrote:
public class debug:MonoBehaviour{
void Start(){
Debug.Log(Profile.profileStamina.ToString());
}
}
It says I need an object reference for the non-static field, method, or property
'Profile.Profile.Stamina'. Easy fix: make everything static (I believe I need to make constructors or something like that to avoid having to use static all the time. A little help with that would be great!). Once error-free, I ran the program and the console outputs 0 for my profile stamina. I am really confused as to what is going on. Sorry this is such a long post, and thanks for any help I get.
I need to pass a value from one class to another. If I am not
mistaken, this would be done through inheritance.
No, you don't need inheritance to pass values from one class to another. If you don't know what inheritance is, you shouldn't be using it. It's very likely you don't need it. The-same thing applies to the static keyword. New programmers tend to make everything static when they don't know what the new keyword is used for.
Simply create a new instance of the Stats script inside the Profile constructor script. To use the Profile script, create a new instance of it which will automatically call the constructor that will create a new instance of the Stats script. You shouldn't be doing this with static variables and functions. Totally unnecessary. Values can be passed to another script with auto property or function but my solution used auto property to make it simple.
public class Stats
{
private int STAMINA;
public int Stamina
{
get { return STAMINA; }
set { STAMINA = value; }
}
}
public class Profile
{
private Stats stats;
private int PROFILE_STAMINA;
//Init only
public Profile()
{
stats = new Stats();
}
//Init with Stats stamina and profileStamina stamina values
public Profile(int stamina, int profileStamina)
{
stats = new Stats();
stats.Stamina = stamina;
PROFILE_STAMINA = profileStamina;
}
//Stamina From Profile
public int profileStamina
{
get { return PROFILE_STAMINA; }
set { PROFILE_STAMINA = value; }
}
//Stamina From Stats
public int Stamina
{
get { return stats.Stamina; }
set { stats.Stamina = value; }
}
}
Usage:
public class debug:MonoBehaviour{
Profile profile = null;
void Start()
{
//Creata new profile and set Stats stamina and ProfileStamina stamina values
profile = new Profile(10, 5);
profile.Stamina = 60;
profile.profileStamina = 60;
Debug.Log(profile.profileStamina.ToString());
}
Also take time and learn about Classes,Properties.
You're trying to access a non-static from a static property.
This code is the main problem:
public static int Stamina{
get{return STAMINA;}
set{STAMINA = value;}
}
STAMINA is defined as private int STAMINA. It isn't static. Quite simply, this means that inside every object of the type baseStats you have an int called STAMINA you can fill in. However, you're not working on an object there; you're in a static function, which is something that can be executed without an object. Since there is no object, there is no STAMINA int either; there's no object to get or fill in that property on.
On that note, your function profileStats() has the same issue; it tries to access the non-static STAMINA as well, again without having any kind of object. Any reference to just plain STAMINA is actually to this.STAMINA, and inside a static, there's no this.
I'm not sure what the purpose of this whole setup is; personally I'd avoid using statics containing global data like that. Instead I'd just keep an object around containing the necessary properties which is simply passed on to any functions that need to access the data in it. But anyway, from what I can see, you simply forgot to put static on that private int STAMINA.
Side note: this is completely unrelated to inheritance. Since Stamina is a public static property, and statics can't be inherited (except in some peculiar advanced cases with inherited generics), your "child class" never even needs the parent class as parent, as long as it references baseStats.Stamina instead of STAMINA. This can easily be shown by making both classes static.

C# creating an array in a singelton class

I want to create an array of Disc which id like to include fields string[] Record, int NumberHeads and string extension. so basically grouping them and instantiate the array once and only once as i dont want more than one of this array in the memory. How can i do this as my fields dont seem to be under the array Disc and if i make them public and run the application i get a null reference exception.
I was initially using a struct but I came to realise these cannot be passed from class to class in C#.
class DiscType
{
private static DiscType[] disc;
private static string[];
public bool discSelect;
public int maxRecord;
public int numberHeads;
public string extension;
public static string[] Record
{
get
{
if (record == null)
{
record = new string[1000];
}
return record;
}
}
public static DiscType[] Disc
{
get
{
if (disc == null)
{
disc = new DiscType[10];
}
return disc;
}
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
for (int i = 0; i < DiscType.Disc.Length; i++)
{
DiscType.Disc[i].Record[i]= "1";
}
}
}
If you want only once instanciation of your array do it like that :
public class Singleton
{
private static Singleton instance;
public string[] MyArray { get; set; }
//better using a List<string>
private Singleton() {
//instanciate MyArray here
}
public static Singleton Instance
{
get
{
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
}
}
After that you just need to call it like that :
Singleton.intance.MyArray
You describe two problems:
After you think you created a DiscType and an array of records, your array of records only contains null values
Your DiscType is not a singleton.
Is Disctype a singleton?
Someone else already described how to create a Singleton, So I wont write this. However I doubt whether DiscType in your design really is a singleton. If you'd describe your design in words, would you talk about the one and only disctype, or would you say: "Although in my designed world it could be that there were several different disctypes, however because of the huge amount of memory and mabye because of the time it takes to create one, it is advised to use only one disctype during the session".
In the latter case, you should not design it as a singleton. The famous gang of four wrote in their book about design patterns (where the singleton is described) as one of the major rules of design:
Design for change
That means, that you should not restrict your design merely for the case that in the current usage it is not needed. If in your current configuration you only need one disctype, just create only one. If in future versions you need two, you don't need to change your disctype.
So careful review your design: are we talking about "the one and only disctype"? or are we only restricting to one because we don't have enough memory?
Why is my array of records empty
To understand this, you need to know the difference between value types and reference types. Simple types and structs are value types. They exist as soon as you declare them. Instances of classes are always reference types: you need to call new ... to create them. If you don't do this, the value is null.
Myclass X;
string text;
int i;
System.Drawing.Point p; // a Point is a struct!
X and text both have a null value, the only thing you can do with them before you assign something to them is compare them with null
i and p already have a value. You can get them and call their methods.
Back to your problem
Your code:
public static string[] Record
{
get
{
if (record == null)
{
record = new string[1000];
}
return record;
}
}
You assign a newly created object to record. the object is an array of strings, which are reference types. You haven't assigned anything to each string, so each string in your array is still null, and you can't do anything with them until you assign something.
The array of strings however is initialized. You can use methods of the array. You can ask for the length of the array. You can also ask for item[3] in which you get the uninitialized (null) string.
List instead of Array
By the way, this method of initializing is a bit unusual. I guess you don't want to reserve memory for records as long as you don't use them. You would have accomplished that by using List.
My advise is to familiarize yourself with class List. It will make your life so much easier. Before long you'll feel the desire to know all collection classes :-)

Defining and using a Global Generic List in WCF Application

I am sending a few separate messages from an asp.net site to my WCF server.
These messages are coming through individually, and I need the server to pick them up, and 'stitch' them together.
What I am trying to do is put those methods in a global List, then using that list in a different class to do my bidding.
So far I have...
variables.cs
class variables
{
public static List<string> MessageStitches { get; set; }
}
Program.cs
if (!string.IsNullOrEmpty(node))
{
variables.MessageStitches.Add(node);
}
But I am getting this error:
Object reference not set to an instance of an object.
Can anyone see where I am going wrong, and how to fix it?
You have not set the variables.MessageStitches property to be a new list.
You have several options, but the best option for you is almost certainly 1 or 2.
1 - Assign a new list in the constructor of variables. However, as your list is static, this will not actually help you, as you may not have instantiated your variables class, and so your constructor will not have run. You can have a static constructor though:
class variables
{
public static List<string> MessageStitches { get; set; }
// Static constructor
static variables()
{
MessageStitches = new List<string>();
}
}
2 - Don't use auto-properties. Instead, have a backing field for your property, which is assigned a value at initialisation:
public class variables
{
private static List<string> messageStitches = new List<string>();
public static List<string> MessageStitches
{
get
{
return messageStitches;
}
set
{
messageStitches = value;
}
}
3 - Check the list before using to ensure it's not null and, if it is, assign a new list then. Again, this will not be threadsafe, unless you take steps to make it so (e.g. by entering a critical section)
if (!string.IsNullOrEmpty(node))
{
if (variables.MessageStitches == null)
{
variables.MessageStitches = new List<string>();
}
variables.MessageStitches.Add(node);
}
Define a constructor in Variable.cs like:
public variables()
{
MessageStitches = new List<string>();
}
or you can do like this :
variables.MessageStitches = new List<string>();
variables.MessageStitches.Add(node);

C# - How to access a static class variable given only the class type?

This is my first time posting on Stack Overflow, so hopefully I did everything right and you guys can help.
I'm wondering if in C# there's a way to access a static variable belonging to a class, when given only the type of the class. For example:
public class Foo
{
public static int bar = 0;
}
public class Main
{
public void myFunc(Type givenType)
{
int tempInt = ??? // Get the value of the variable "bar" from "Foo"
Debug.WriteLine("Bar is currently :" + tempInt);
}
}
// I didn't run this code through a compiler, but its simple enough
// that hopefully you should get the idea...
It's hard to describe the context of needing to know this, but I'm making a game in XNA and I'm trying to use reference counting to reduce the complexity of the design. I have objects in the game and power-ups that can apply an effect them (that stays on the objects). Power-ups can die but their effects can still linger on the objects, and I need to keep track of if any effects from a power-up are still lingering on objects (thus, reference counting). I plan to make a "PowerUpEffect" class (for each type of power-up) with a static integer saving the number of objects still affected by it, but the design of the rest of the game doesn't work well with passing the PowerUpEffect all the way down to the object for it to call a method of the PowerUpEffect class.
I'm hoping to pass only the PowerUpEffect's type (using something like "typeOf()") and use that type to reference static variables belonging to those types, but I have no idea how to do it or if it's even possible.
I'd be glad to even find work-arounds that don't answer this questions directly but solve the problem in a simple and elegant design. =)
Help! (and thanks!)
If you only have the Type handle, you can do this:
var prop = givenType.GetProperty("bar");
var value = prop.GetValue(null);
I would use a Dictionary instead, which are probably the most concise way of mapping one set of values to another. If you are associating int values with Types, then do something like:
public static readonly Dictionary<Type, int> sTypeValues =
new Dictionary<Type, int>
{
{ typeof(Type1), 5 },
{ typeof(Type2), 10 },
{ typeof(Type3), 2 },
{ typeof(Type4), 3 },
{ typeof(Type5), -7 }
};
your function then becomes:
public void myFunc(Type givenType)
{
int tempInt = sTypeValues[givenType];
Debug.WriteLine("Bar is currently :" + tempInt);
}
int tempInt = (int) givenType.GetField("bar").GetValue(null);
Okay, so you have a collection of powerups, and you want to have an integer associated with each of those powerups. Rather than having a lot of classes, each with a static integer, you can have a single static collection which holds onto all of the powerups and their associated integer values.
public static class MyPowerupInfo
{
public static Dictionary<PowerUp, int> PowerUps {get; private set;}
static MyPowerupInfo
{
PowerUps = new Dictionary<PowerUp, int>();
PowerUps.Add(*some power up object goes here*, 0);
//TODO add other power ups
}
}
Then to use it you can do something like:
int powerupCount = MyPowerupInfo.PowerUps[wickedAwesomePowerup];
or:
public static void IncrementPowerup(Powerup powerup)
{
MyPowerupInfo.PowerUps[powerup] = MyPowerupInfo.PowerUps[powerup]+1;
}
If am getting you correc, this might give you some idea:
using System;
using System.Reflection;
public class RStatic
{
private static int SomeNumber {get; set;}
public static object SomeReference {get; set;}
static RStatic()
{
SomeReference = new object();
Console.WriteLine(SomeReference.GetHashCode());
}
}
public class Program
{
public static void Main()
{
var rs = new RStatic();
var pi = rs.GetType().GetProperty("SomeReference", BindingFlags.Static | BindingFlags.Public); // i have used GetProperty in my case
Console.WriteLine(pi.GetValue(rs, null).GetHashCode());
}
}
Are you assuming if the name of the field you're trying to access (for example, for the class "foo", the field "bar") is a different field based on the Type parameter?
If the name of the field is known based on a finite number of allowable types, you should be able to determine it with a switch statement. For example:
public class Foo
{
public static int bar = 0;
}
public class Baz
{
public static int bing = 0;
}
public class Main
{
public void myFunc(Type givenType)
{
switch (givenType.ToString())
{
case "Foo":
Debug.WriteLine("Bar is currently :" + Foo.bar);
break;
case "Baz":
Debug.WriteLine("Bing is currently :" + Baz.bing);
break;
}
}
}

Categories

Resources