Running the same method for different variables in a class - c#

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)

Related

Updating Data in your model directly from a class

I'm making a simple game as a practice project based around random events, to make it easier to add new events I’ve decided to use a keyword system where each event gets keywords assigned to them that are then used to process the event, this can be as simple as displaying as message, changing data in the model or rolling again on the random table.
I have a class that randomly decides an event and returns a List of strings with keywords.
I want to make a class where all the keywords are stored as methods that can then be called with the list.
Something like this:
class Keyword
{
public void InputKeywords(List<string> Ikeywords)
{
foreach (var item in Ikeywords)
{
switch (item)
{
case "keyword0":
keyword0();
break;
case "keyword1":
keyword0();
break;
case "keyword2":
keyword0();
break;
}
}
}
private void keyword0()
{
//do something
}
private void keyword1()
{
//do something
}
private void keyword2()
{
//do something
}
}
Now the problem I’m facing is updating the data in the model from the keywords class.
Because the events are chosen at random I don't know for each event what data to send to the class to have it update it.
The solutions I've come up with myself:
Make my model static, no more issues with accessing data, Google tells me this is frowned upon and should be avoided.
Send the model to the Keyword class, do some magic, and return the model. Would be an easy solution but feels wrong to me, from what I've come to understand about MVVM is that the data should be updated from the viewmodel, but I could be thinking too much inside of the box.
Gather all possible data to be changed into a seperate class, send that to the keyword class and update the model afterwards. This sounds like a hassle and feels like I'm just moving the problem elsewhere.
I feel like I'm missing the "right" way of doing this. What would be the "best" approach?
First of all the naming of the keyword class feels misleading here. It is basically an event handler, so I would also name it like on (e.g. RandomEventGenerator)
To your problem I would also not recommend you to use static models. Your testability will suffer from it since you won't use dependency injection there. This being said your second approach seems to go into the right direction. I would suggest to use inject an EventInvoker Interface.
public interface IEventInvoker
{
public void RaiseEvent();
}
This can be implemented in an operator, which has access to your data model and has predefined actions to modify your data.
public class WeatherOperator : IEventInvoker
{
private readonly WeatherEngine _weatherEngine;
public WeatherOperator(WeatherEngine weatherEngine)
{
_weatherEngine = weatherEngine;
}
public void RaiseEvent()
{
StartSunshine();
}
public void StartSunshine()
{
_weatherEngine.RemoveClouds();
_weatherEngine.SetSunPosition(DayTimes.Noon);
}
public void LetItRain()
{
_weatherEngine.SetCloudes(CloudModes.FullCover);
_weatherEngine.SetRain(RainIntesity.Medium);
}
}
With a list of the IEventInvoker you can then go to your EventHandler.
public class RandomEventGenerator
{
private readonly List<IEventInvoker> _eventInvoker;
private readonly Dictionary<string, Action> _eventDictionary;
public RandomEventGenerator(List<IEventInvoker> eventOperator, List<string> keywords)
{
_eventInvoker = eventOperator;
_eventDictionary = RegisterKeywordsToRandomEvents(keywords);
}
private Dictionary<string,Action> RegisterKeywordsToRandomEvents(List<string> keywords)
{
var eventDictionary = new Dictionary<string, Action>();
foreach (var keyword in keywords)
{
var random = new Random();
var index = random.Next(_eventInvoker.Count);
eventDictionary.Add(keyword,_eventInvoker[index].RaiseEvent);
}
return eventDictionary;
}
public void EventByKeyword(string Keyword)
{
_eventDictionary[Keyword].Invoke();
}
public void RandomEvent()
{
var random = new Random();
var index = random.Next(_eventInvoker.Count);
_eventInvoker[index].RaiseEvent();
}
}
Please note that I, to keep it small, didn't used null checks or input validations here, which is highly recommended.
With this approach you have a clear cut bettween your model/data and your viewmodel/data accesor.

Is there a way for a getter in C# to cache its result in-line?

I've been working on a Discord bot and one of my abstract classes that represents servers ("Bot Contexts") contains the following data.
public virtual Command[] ContextSpecificCommands { get; } = null;
In user-defined Contexts I expect them to override this (if the server that has this code needs to). There's an issue, however, which is that I expect Commands to be singletons in the scope of a Context. This means that CommandFoo can exist only once in CoolContextNumberOne, and can also exist in CoolContextNumberTwo (as a separate instance of CommandFoo), but a single context cannot have two instances of CommandFoo in it.
My issue comes in with the behavior of getters. If the user does this...
public override Command[] ContextSpecificCommands => new Command[] {
new CommandFoo()
};
Then this will instantiate CommandFoo every time ContextSpecificCommands is referenced.
Is there any way to ensure that ContextSpecificCommands is cached in-line so that it only instantiates that container array once? I'd like to avoid requiring the user to specify a field and point to that field if possible.
This code was for the intellectual exercise, it is not recommended!
If you are willing to force the implementors of your BotContexts to use a specific form, then you can insert a type of singleton pattern into the property definition.
Consider:
public static class Singleton {
public static T For<T>(Func<T> makeSingleton) => Singleton<T>.For(makeSingleton);
}
public static class Singleton<T> {
static Dictionary<Func<T>, T> Cache = new Dictionary<Func<T>, T>();
public static T For(Func<T> makeSingleton) {
T singleton;
if (!Cache.TryGetValue(makeSingleton, out singleton)) {
singleton = makeSingleton();
Cache[makeSingleton] = singleton;
}
return singleton;
}
}
Now you can use this like so:
public class CoolContextNumberOne : BotContexts {
public override Command[] ContextSpecificCommands => Singleton.For(() => new Command[] { new CommandFoo() });
}
public class CoolContextNumberTwo : BotContexts {
public override Command[] ContextSpecificCommands => Singleton.For(() => new Command[] { new CommandFoo() });
}
Each CoolContext will create one instance of CommandFoo regardless of how many times ContextSpecificCommands is called.
Since in C# the use of a new expression will always generate a new object, it is difficult (impossible?) to see how you could have the code the same and figure out when to generate a new object and when to return an existing object (e.g. if a Command was actually a proxy object). If you didn't mind a dependency on optimization being enabled, StackFrame and GetILOffset could help, but would probably fail in debug mode. And be very brittle.
It may be possible to hide the use of Singleton in the types of Commands by using dynamic and Expando but that seems like an even worse idea.
This is not natively possible without adding extra code.
In order for a result to cache, a separate backing field must be created and the code must be set up to work with this field.
In order to resolve my dilemma, I have altered my code from:
// User will override this.
public virtual Command[] ContextSpecificCommands { get; } = null;
To:
// User will override this.
protected virtual Command[] ContextSpecificCommands { get; } = null;
// These control the cache.
private bool HasPopulatedCommandCache = false;
private Command[] CommandCache = null;
// Things will reference this to get ahold of commands.
public Command[] Commands {
get {
if (!HasPopulatedCommandCache) {
HasPopulatedCommandCache = true;
CommandCache = ContextSpecificCommands;
}
return CommandCache;
}
}
This allows the code to meet all of the goals specified in my original question. The user's class can use an in-line expression to define their commands without the worry of this array being instantiated every time it is referenced.

How not to return a mutable from a method and exposing class internals

I think that is a commonly asked question and I believe I have covered the bases well, as in how objects, structs or value types are passed between functions. Let us assume I have the following classes:
public class User{
public int xCoor{get;set}
public int yCoor{get;set}
}
public class UserManager{
Dictionary<int,User> userMapping = new Dictionary<int,User>();
public void AddUser(User user){//stuff}
public void RemoveUser(User user){//stuff}
public IEnumerable<User> GetAllUsers(){return userMapping.Values;}
}
public class UserConsumer{
private UserManager;
public void GetUserCoordinates(){
var listThatExposesInternals = UserManager.GetAllUsers().ToList();
listThatExposesInternals.Foreach(user => user.xCoor = user.yCoor = 0);
// Now that I altered the internals of the class, it is messed up
// I only want the consumer to be able read
}
}
How can I make sure that the internals of the User class stays intact. I am aware that for this problem it is also appropriate to expose xCoor and yCoor rather than the whole User class but most of the time I face the problem (need?) to return the reference to the class. I appreciate any advises.
There are a number of approaches you could take. If there is never a situation where xCoor and yCoor should be changed after User is instantiated, you could require the values in its constructor and make the setter private to ensure they can't be changed outside this class.
public class User
{
public User(int xCoor, int yCoor)
{
this.xCoor = xCoor;
this.yCoor = yCoor;
}
public int xCoor{get; private set;}
public int yCoor{get; private set;}
}
If you do need User to be mutable, but want to discourage changing the properties under certain circumstances, you could create an interface for User to implement that only has getters on those properties. However, people could still cast their IReadableUser as a User and access those properties.
Another option would be to create a new class that wraps a User object, and only exposes getters which read the properties from an actual User instance, but cannot set those same properties. This option could be combined with the IReadableUser approach above, to hide the implementation details of the returned object while still preventing people from casting the object to a User to change its values.
public interface IReadOnlyUser
{
int xCoor {get;}
int yCoor {get;}
}
internal class ReadOnlyUser : IReadOnlyUser
{
private readonly User user;
public ReadOnlyUser(User user)
{
this.user = user;
}
public int xCoor{get { return this.user.xCoor; }}
public int yCoor{get { return this.user.yCoor; }}
}
public IEnumerable<IReadOnlyUser> GetAllUsers()
{
return userMapping.Values
.Select(u => (IReadOnlyUser) new ReadOnlyUser(u));
}
Yet another option would be to allow the users to mutate the values you return, but ensure these values are copied values so the next time someone asks for the list of users they're seeing instances that haven't been changed.
public IEnumerable<User> GetAllUsers()
{
return userMapping.Values
.Select(u => new User { xCoor = u.xCoor, yCoor = u.yCoor });
}
If you had more reference-based values in your User class, your Select statement would need to create new instances of those as well. If that becomes burdensome, you might consider giving each class a copy constructor to ensure that the responsibility for copying values is consolidated into the part of code where it's most likely to be noticed and fixed when things change.
My apologies for marking this as an answer. Lost my previous account and am not having enough reputation to post this as a comment (not yet).
One way to do it is to make all the Properties readOnly and set the values through the constructor. However, I am not sure if that works for you. If the behavior of class modifies the state of object, then that may throw a wrench in the wheel.
About the List, if the list returns a copy of the object (i.e. returns the copy of the List) then that should be good. If you want the individual objects to be not mutable, you have 2 options
Make copy of individual data containers (objects) instead of just copying the references (which this one does)
Force the data container to be non-mutable by exposing the properties as get only and make the setters as private.
Hope that helps.
Maybe removing the sets or making them private :
public class User{
public int xCoor{get;}
public int yCoor{get;}
}
or
public class User{
public int xCoor{get; private set;}
public int yCoor{get; private set;}
}
There are a few ways. I am suspecting that you merely need to remove the "set" from each set/get.
you could have:
public class User
{
protected int _xCoor = 0;
protected int _yCoor = 0;
public int xCoor
{
get { return _xCoor; }
}
public int yCoor
{
get { return _yCoor; }
}
}
In my example case, in order to change the values of _xCoor and _yCoor, you would have to created a class that inherits from the User class.

How should I remove elements from a generic list based on the list s object's inclusion of elementfrom another list in C# using predicate logic?

I am trying to learn C# by making a simple program that shows the user sushi rolls given their desired ingredients. i.e. a user wants a roll with crab, and the program will spit out a list of sushi rolls that contain crab.
I've created a Roll class
public class Roll
{
private string name;
private List<string> ingredients = new List<string>();
}
With some getters and setters and other various methods.
In the GUI, I have some checkboxes which each call an update() method from the Control class, which will then need to check a list of rolls against a list of ingredients given by the GUI checkboxes. What I have is this
class Controller
{
static List<Roll> Rolls = new List<Roll>();
static RollList RL = new RollList();
static List<String> ingredients = new List<String>();
static Roll roll = new Roll();
}
public void update
{
foreach(Roll roll in Rolls)
{
foreach (String ingredient in ingredients)
if (!roll.checkForIngredient(ingredient))
Rolls.Remove(roll);
}
}
But a System.InvalidOperationException is thrown saying that because the collection was modified, the operation can't execute. OK, that's fair, but then what's the best way to do this? Here on Stack Overflow there's a post about removing elements from a generic list while iterating over it.
This was good and pointed me in the right direction, but unfortunately, my predicate condition simply doesn't match the top answer's.
It would have to iterate over the ingredients list, and I'm not even sure that's possible...
list.RemoveAll(roll => !roll.containsIngredient(each string ingredient in ingredients) );
shudder
I've tried the for loop, but I can't seem to get the enumeration to work either, and I wonder if it's even necessary to enumerate the class for just this method.
So I come here to try and find an elegant, professional solution to my problem. Keep in mind that I'm new to C# and I'm not all too familiar with predicate logic or enumeration on classes.
To use RemoveAll you can rewrite your condition to this:
list.RemoveAll(roll => !ingredients.All(roll.checkForIngredient));
This exploits the fact that when the compiler sees this, it will effectively rewrite it to this:
list.RemoveAll(roll => !ingredients.All(i => roll.checkForIngredient(i)));
Which is what you want. If not all the ingredients are present, remove the roll.
Now, having said that, since you say you're a beginner, perhaps you feel more comfortable keeping your loop, if you could just make it work (ie. stop crashing due to modifying the loop). To do that, just make a copy of the collection and then loop through the copy, you can do this by just modifying the foreach statement to this:
foreach(Roll roll in Rolls.ToList())
This will create a list based copy of the Rolls collection, and then loop on that. The list will not be modified, even if Rolls is, it is a separate copy containing all the elements of Rolls when it was created.
As requested in the comments, I'll try to explain how this line of code works:
list.RemoveAll(roll => !ingredients.All(roll.checkForIngredient));
The RemoveAll method, which you can see the documentation for here takes a predicate, a Predicate<T>, which is basically a delegate, a reference to a method.
This can be a lambda, syntax that creates an anonymous method, using the => operator. An anonymous method is basically a method declared where you want to use it, without a name, hence the anonymous part. Let's rewrite the code to use an anonymous method instead of a lambda:
list.RemoveAll(delegate(Roll roll)
{
return !ingredients.All(roll.checkForIngredient);
});
This is the exact same compiled code as for the lambda version above, just using the bit more verbose syntax of an anonymous method.
So, how does the code inside the method work.
The All method is an extension method, found on the Enumerable class: Enumerable.All.
It will basically loop through all the elements of the collection it is extending, in this case the ingredients collection of a single roll, and call the predicate function. If for any of the elements the predicate returns false, the result of calling All will also be false. If all the calls return true, the result will also be true. Note that if the collection (ingredients) is empty, the result will also be true.
So let's try to rewrite our lambda code, which again looked like this:
list.RemoveAll(roll => !ingredients.All(roll.checkForIngredient));
Into a more verbose method, not using the All extension method:
list.RemoveAll(delegate(Roll roll)
{
bool all = true;
foreach (var ingredient in ingredients)
if (!roll.checkForIngredient(ingredient))
{
all = false;
break;
}
return !all;
});
This now starts to look like your original piece of code, except that we're using the RemoveAll method, which needs a predicate that returns whether to remove the item or not. Since if all is false, we need to remove the roll, we use the not operator ! to reverse that value.
Since you are both new to C# but also asked for an elegant solution, I will give you an example of how to solve this using a more object-oriented approach.
First of all, any "thing" of significance should be modeled as a class, even if it has just one property. This makes it easier to extend the behavior later on. You already defined a class for Roll. I would also add a class for Ingredient:
public class Ingredient
{
private string _name;
public string Name
{
get { return _name; }
}
public Ingredient(string name)
{
_name = name;
}
}
Note the Name property which only has a getter, and the constructor which accepts a string name. This might look like unnecessary complexity at first but will make your code more straightforward to consume further down the road.
Next, we'll modify your Roll class according to this guideline and give it some helper methods that make it easier for us to check if a roll contains a certain (list of) ingredients:
public class Roll
{
private string _name;
private List<Ingredient> _ingredients = new List<Ingredient>();
public string Name
{
// By only exposing the property through a getter, you are preventing the name
// from being changed after the roll has been created
get { return _name; }
}
public List<Ingredient> Ingredients
{
// Similarly here, you are forcing the consumer to use the AddIngredient method
// where you can do any necessary checks before actually adding the ingredient
get { return _ingredients; }
}
public Roll(string name)
{
_name = name;
}
public bool AddIngredient(Ingredient ingredient)
{
// Returning a boolean value to indicate whether the ingredient was already present,
// gives the consumer of this class a way to present feedback to the end user
bool alreadyHasIngredient = _ingredients.Any(i => i.Name == ingredient.Name);
if (!alreadyHasIngredient)
{
_ingredients.Add(ingredient);
return true;
}
return false;
}
public bool ContainsIngredients(IEnumerable<Ingredient> ingredients)
{
// We use a method group to check for all of the supplied ingredients
// whether or not they exist
return ingredients.All(ContainsIngredient);
// Could be rewritten as: ingredients.All(i => ContainsIngredient(i));
}
public bool ContainsIngredient(Ingredient ingredient)
{
// We simply check if an ingredient is present by comparing their names
return _ingredients.Any(i => i.Name == ingredient.Name);
}
}
Pay attention to the ContainsIngredient and ContainsIngredients methods here. Now you can do stuff like if (roll.ContainsIngredient(ingredient)), which will make your code more expressive and more readable. You'll see this in action in the next class that I'm going to add, RollCollection.
You are modeling collections of food to pick from, presumably in the context of a restaurant menu or some similar domain. You might as well go ahead and model just that: a RollCollection. This will allow you to encapsulate some meaningful logic inside of the collection.
Again, this sort of thing tends to require some boilerplate code and may look overly complex at first, but it will make your classes easier to consume. So let's add a RollCollection:
public class RollCollection : IEnumerable<Roll>
{
private List<Roll> _rolls = new List<Roll>();
public RollCollection()
{
// We need to provide a default constructor if we want to be able
// to instantiate an empty RollCollection and then add rolls later on
}
public RollCollection(IEnumerable<Roll> rolls)
{
// By providing a constructor overload which accepts an IEnumerable<Roll>,
// we have the opportunity to create a new RollCollection based on a filtered existing collection of rolls
_rolls = rolls.ToList();
}
public RollCollection WhichContainIngredients(IEnumerable<Ingredient> ingredients)
{
IEnumerable<Roll> filteredRolls = _rolls
.Where(r => r.ContainsIngredients(ingredients));
return new RollCollection(filteredRolls);
}
public bool AddRoll(Roll roll)
{
// Similar to AddIngredient
bool alreadyContainsRoll = _rolls.Any(r => r.Name == roll.Name);
if (!alreadyContainsRoll)
{
_rolls.Add(roll);
return true;
}
return false;
}
#region IEnumerable implementation
public IEnumerator<Roll> GetEnumerator()
{
foreach (Roll roll in _rolls)
{
yield return roll;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
}
WhichContainIngredients is the thing we were really looking for, as it allows you to do something like this:
// I have omitted the (proper) instantiation of Rolls and ChosenIngredients for brevity here
public RollCollection Rolls { get; set; }
public List<Ingredient> ChosenIngredients { get; set; }
public void Update()
{
Rolls = Rolls.WhichContainIngredients(ChosenIngredients);
}
This is simple and clean, just the sort of thing you want to be doing in your presentation layer. The logic to accomplish your requirement is now nicely encapsulated in the RollCollection class.
EDIT: a more complete (but still simplified) example of how your Controller class might end up looking like:
public class Controller
{
private RollCollection _availableRolls = new RollCollection();
private List<Ingredient> _availableIngredients = new List<Ingredient>();
public RollCollection AvailableRolls
{
get { return _availableRolls; }
}
public List<Ingredient> AvailableIngredients
{
get { return _availableIngredients; }
}
public RollCollection RollsFilteredByIngredients
{
get { return AvailableRolls.WhichContainIngredients(ChosenIngredients); }
}
public List<Ingredient> ChosenIngredients { get; set; }
public Controller()
{
ChosenIngredients = new List<Ingredient>();
InitializeTestData();
}
private void InitializeTestData()
{
Ingredient ingredient1 = new Ingredient("Ingredient1");
Ingredient ingredient2 = new Ingredient("Ingredient2");
Ingredient ingredient3 = new Ingredient("Ingredient3");
_availableIngredients.Add(ingredient1);
_availableIngredients.Add(ingredient2);
_availableIngredients.Add(ingredient3);
Roll roll1 = new Roll("Roll1");
roll1.AddIngredient(ingredient1);
roll1.AddIngredient(ingredient2);
Roll roll2 = new Roll("Roll2");
roll2.AddIngredient(ingredient3);
_availableRolls.AddRoll(roll1);
_availableRolls.AddRoll(roll2);
}
}
I am trying to learn C# by making a simple program that shows the user
sushi rolls given their desired ingredients. i.e. a user wants a roll
with crab, and the program will spit out a list of sushi rolls that
contain crab.
Here's my solution to the given problem:
public class Roll
{
public string Name { get; set; }
private List<string> ingredients = new List<string>();
public IList<string> Ingredients { get { return ingredients; } }
public bool Contains(string ingredient)
{
return Ingredients.Any(i => i.Equals(ingredient));
}
}
You can use the LINQ extension method .Where to filter your collection of Rolls
public class Program
{
static void Main()
{
var allRolls = new List<Roll>
{
new Roll
{
Name = "Roll 1",
Ingredients = { "IngredientA", "Crab", "IngredientC" }
},
new Roll
{
Name = "Roll 2",
Ingredients = { "IngredientB", "IngredientC" }
},
new Roll
{
Name = "Roll 3",
Ingredients = { "Crab", "IngredientA" }
}
};
var rollsWithCrab = allRolls.Where(roll => roll.Contains("Crab"));
foreach (Roll roll in rollsWithCrab)
{
Console.WriteLine(roll.Name);
}
}
}
From what I see you're trying to remove all rolls that don't contain crab from your list of rolls. A better approach is to filter out those rolls that don't contain crab (using .Where), you can then use .ToList() if you need to manipulate the whole list directly rather than iterating through the collection (fetching one item at a time).
You should read up on Delegates, Iterators, Extension Methods and LINQ to better understand what's going on under the covers.

Keep my list/dictionary as globally accessible

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.

Categories

Resources