Say I have a list of member, each of which is a custom object:
public class pail
{
public string milk;
public string water;
public string butter;
public string beer;
}
public class AddToPail()
{
private List<pail> _pailList = new List<pail>();
PSVM(String[] args)
{
for(int i = 0; i < 200; i++)
{
pail newPail = new Pail();
switch(i)
{
case 1:
{
newPail.milk = "This pail has milk";
}
break;
case 2:
{
newPail.butter = "This pail has butter";
}
break;
case 3:
{
newPail.water = "This pail has water";
}
break;
case 4:
{
newPail.beer = "This pail has beer";
}
break;
}
_pailList.Add(newPail);
}
foreach (pail thisPail in _pailList)
{
using (StreamWriter SW = new StreamWriter(#"C:\pail.txt")
{
if (!thisPail.milk.IsNullOrEmpty())
{
SW.WriteLine(thisPail.milk);
}
else if (!thisPail.butter.IsNullOrEmpty())
{
SW.WriteLine(thisPail.butter);
}
else if (!thisPail.beer.IsNullOrEmpty())
{
SW.WriteLine(thisPail.beer);
}
else if (!thisPail.water.IsNullOrEmpty())
{
SW.WriteLine(thisPail.water);
}
else
{
Console.Writeline("oops");
}
}
}
}
}
Say I want to set up a StreamWriter that only prints the true values without having to write a million if, else if, else statements... is there an easy way or library to do this in C#? I'm basically looking for a way to only print out true values in a neat, concise way. Does anyone have any advice as to how I should approach this?
Thank you very much!
EDIT
So the ultimate goal of this is that I have an object that has around 20 members. The object is automatically populated, and the populating script can leave some of the members empty. I'd like to be able to print the members in a CSV format, and not have to have 20 if statements to see if a particular member in the object has been instantiated before outputting via the streamwriter.
Edit 2
I changed my code to be a little closer to what I needed it to do. Sorry for the previous poor explanation.
I think you should refactor your program a little bit. For starters, I would use an enum for bucket contents:
public enum EBucketContents { Milk, Water, Butter, Beer };
Then, instead of having a list of booleans, you can use a dictionary:
var pail = Dictionary<EBucketContents,bool>();
Now it's a simple matter to only output the ones that are true:
foreach( var kvp in pail.Where( x => x.Value ) ) {
SW.WriteLine( "pail has " + kvp.Key.ToString().ToLower() )
}
If you just want to save some typing, use this extension method:
internal static class Extensions
{
public static void WriteLineIf(this TextWriter tw, bool condition, string text)
{
if (condition)
{
tw.WriteLine(text);
}
}
}
But it looks like only one of those bools can be true, since you're using else if blocks.
In that case, use and enum
internal enum Pail
{
Butter,
Milk,
Water,
Beer
}
Can you just use a Dictionary where the key is the field name and the value is the fields value. This way you don't need to check if the output is filled or not - you just output all fields
Your populating script can populate the dictionary keys only if they are set
Then your streamwriter can just go
foreach(KeyValuePair<string, string> kvp in fieldsDict)
sw.Write("Key: " + kvp.Key + ", Value: " + kvp.Value);
Or even just a list of string/or enum
e.g.
public class pail
{
public List<string> Fields = new List<string>();
}
public class AddToPail()
{
private List<pail> _pailList = new List<pail>();
PSVM(String[] args)
{
for(int i = 0; i < 200; i++)
{
pail newPail = new Pail();
switch(i)
{
case 1:
{
newPail.Fields.Add("This pail has milk");
}
break;
*** SNIP
Of course using a Dictionary could solve your problem , but I'm not really fond of this kind of solution, since it makes you lose some control over what you are putting in, e.g you could end up with a pail having airplanes... I'd refactor your code in something like this, trying to give every class its own responsabilities (BTW I don't like AddToPail as a class name, it's more a method name):
public class Pail
{
public string milk;
public string water;
public string butter;
public string beer;
private bool everythingEmpty = true;
public Pail(int i)
{
switch(i)
{
case 1:
{
milk = "This pail has milk";
everythingEmpty = false;
}
break;
case 2:
{
butter = "This pail has butter";
everythingEmpty = false;
}
break;
case 3:
{
water = "This pail has water";
everythingEmpty = false;
}
break;
case 4:
{
beer = "This pail has beer";
everythingEmpty = false;
}
break;
}
}
public void WriteToStream(StreamWriter SW)
{
if (everythingEmpty)
{
Console.Writeline("oops");
return;
}
WriteToStream(milk, SW);
WriteToStream(butter, SW);
WriteToStream(beer, SW);
WriteToStream(water, SW);
}
public static void WriteToStream(string content, StreamWriter SW)
{
if (!content.IsNullOrEmpty())
{
SW.WriteLine(content);
}
}
}
public class AddToPail()
{
private List<pail> _pailList = new List<pail>();
PSVM(String[] args)
{
for(int i = 0; i < 200; i++)
{
pail newPail = new Pail(i);
_pailList.Add(newPail);
}
foreach (pail thisPail in _pailList)
{
using (StreamWriter SW = new StreamWriter(#"C:\pail.txt")
{
thisPail.WriteToStream(SW);
}
}
}
}
Related
Create a property called Ingredients.
Create a GetCost method which calculates the total cost of the ingredients used to make the smoothie.
Create a GetPrice method which returns the number from GetCost plus
the number from GetCost multiplied by 1.5. Round to two decimal
places.
Create a GetName method which gets the ingredients and puts
them in alphabetical order into a nice descriptive sentence. If there are multiple ingredients, add the word "Fusion" to the end but otherwise add "Smoothie". Remember to change "-berries" to "-berry"
..............................
i am stuck here ! can you help me with this !
.........................
using System;
using System.Collections.Generic;
using System.Globalization;
namespace test
{
class Smoothie
{
private string[] _ingredients;
private double Cost;
public Smoothie() { }
public Smoothie(string[] p_ingredients)
{
this._ingredients = p_ingredients;
}
public string[] Ingredients
{
get { return this._ingredients; }
set { this._ingredients = value; }
}
public double GetCost()
{
double Cost = 0;
return this.Cost;
}
public string GetPrice()
{
return Convert.ToString(this.GetCost() * 2.5);
}
public string GetName()
{
List<string> names = new List<string>();
foreach (string name in this._ingredients)
{
names.Add(name);
}
if (names.Count < 2)
{
names.Add("Smoothie");
}
else
{
names.Sort();
names.Add("Fusion");
}
return string.Join(" ", names);
}
}
class Program
{
static void Main(string[] args)
{
Smoothie smoothie = new Smoothie();
List<string> names = new List<string>();
string userInput = Console.ReadLine();
switch (userInput)
{
case "Strawberries":
names.Remove("Straw-berries");
names.Add("Straw-berry");
break;
case "2":
if (names.Contains("Banana"))
{
}
break;
case "3":
if (names.Contains("Mango"))
{
Console.WriteLine("Mango have already been added!");
}
break;
}
}
}
}
So I have been looking around and it seems like the correct answer to getting rid of big switch case is polymorphism, but I just can't figure out how I can change this from conditionnal to poplymorphic. Is this the right solution here?
Console.WriteLine(#"Menu");
Console.WriteLine(#"1.Create Account");
Console.WriteLine(#"2.ATM");
Console.WriteLine(#"3.Account info");
Console.Write(#"Please enter your selection: ");
var menuChoice = int.Parse(Console.ReadLine());
switch (menuChoice)
{
case 1:
atm.CreateAccount();
break;
case 2:
//Console.WriteLine(#"1.Deposit Or Withdraw");
Console.WriteLine(#"1.Deposit");
Console.WriteLine(#"2.Withdraw");
Console.Write(#"Please enter your selection: ");
var atmMenuChoice = int.Parse(Console.ReadLine());
switch (atmMenuChoice)
{
case 1:
atm.Deposit();
break;
case 2:
atm.Withdraw();
break;
default:
Console.WriteLine(#"Invalid selection!");
break;
}
break;
case 3:
atm.AccountInfo();
break;
default:
Console.WriteLine(#"Invalid selection!");
break;
}
}
In situations like this I tend to use a Dictionary<string, Action> to lookup what to do for each input.
Something like:
var actions = new Dictionary<string, Action>
{
{ "1", atm.CreateAccount }
{ "2", AtmSelection } //This would do the same as below with the atmActions dictionary
{ "3", atm.AccountInfo }
}
var atmActions = new Dictionary<string, Action>
{
{ "1", atm.Deposit }
{ "2", atm.Withdraw }
}
var input = GetInput(); //From stdin as you do currently
if (actions.TryGetValue(input, out var action))
{
action();
}
else
{
Console.WriteLine("Invalid Selection");
}
I personally find this easier to read than a massive nested switch statement
The preference for polymorphism over a switch usually applies when you're using some sort of serialization framework. Imagine that your int is the serialized representation of a member of a class of singletons, all of which have a particular method that operates on (or visits) your atm object. Then you could deserialize the instance and call that method:
var foo = deserializer.deserialize(intVal);
foo.doStuff(atm);
There's still a switch involved, but it's inside the serialization framework and you don't have to maintain it. If you want to implement a similar pattern without a serialization framework, you'll have to write the switch yourself. The benefit is that you can separate the switch from the rest of the logic:
Foo GetFoo(int type) {
// switch on type
}
var foo = GetFoo(intVal);
foo.doStuff(atm);
This pattern developed in languages that do not (or did not) have function pointers or the equivalent. In languages that do have function pointers, a map of int values to functions as suggested in another answer would essentially accomplish the same thing.
I may have gone a little crazy here, but this works in a similar way to Scott's answer.
static IEnumerable<MenuItem> RootMenu;
static void Main(string[] args)
{
RootMenu = BuildRootMenu();
MenuItem.DisplayMenu(RootMenu, new Atm());
}
/// <summary>
/// Creates the entire menu
/// </summary>
static IEnumerable<MenuItem> BuildRootMenu()
{
MenuItem item1 = new MenuItem() { DisplayText = "Create Account", AtmAction = (a) => a.CreateAccount() };
MenuItem item2_1 = new MenuItem() { DisplayText = "Deposit", AtmAction = (a) => a.Deposit() };
MenuItem item2_2 = new MenuItem() { DisplayText = "Withdraw", AtmAction = (a) => a.Withdraw() };
MenuItem item2 = new MenuItem() { DisplayText = "ATM", AtmAction = (a) => MenuItem.DisplayMenu(new List<MenuItem> { item2_1, item2_2 }, a) };
MenuItem item3 = new MenuItem() { DisplayText = "Account Info", AtmAction = (a) => a.CreateAccount() };
return new List<MenuItem> { item1, item2, item3 };
}
class MenuItem
{
public String DisplayText;
public Action<Atm> AtmAction = null;
public void Execute(Atm atm)
{
AtmAction(atm);
DisplayMenu(RootMenu, atm);
}
public static void DisplayMenu(IEnumerable<MenuItem> menuItems, Atm atm)
{
int i = 1;
foreach (var mi in menuItems)
{
Console.WriteLine(i + ": " + mi.DisplayText);
i++;
}
var rk = Console.ReadKey();
menuItems.ToArray()[int.Parse(rk.KeyChar.ToString()) - 1].Execute(atm);
}
}
class Atm
{
public void Deposit()
{
Console.WriteLine("Ran Deposit");
}
public void Withdraw()
{
Console.WriteLine("Ran Withdraw");
}
public void CreateAccount()
{
Console.WriteLine("Ran CreateAccount");
}
public void AccountInfo()
{
Console.WriteLine("Ran AccountInfo");
}
I am just trying to understand the different output of almost similar code. The only difference is that in first case i store queries temporarily and then do a union. In second case I do it in one statement.
First outputs
BMW
Honda
Second outputs
BMW
Honda
Harley
Enfield
static void Main(string[] args)
{
var queries = GetCar().Cast<Vehicle>();
queries.Union(GetBike());
var queries1 = GetCar().Cast<Vehicle>().Union(GetBike());
//First case
foreach (Vehicle v in queries)
Console.WriteLine(v.Manufacturer);
Console.ReadLine();
//Second case
foreach (Vehicle v in queries1)
Console.WriteLine(v.Manufacturer);
Console.ReadLine();
}
public static IEnumerable<Car> GetCar()
{
for(int i=0; i<2; i++)
{
Car car = new Car();
if(i == 0)
{
car.Manufacturer = "BMW";
car.Model = "7 series";
}
else
{
car.Manufacturer = "Honda";
car.Model = "Civic";
}
yield return car;
}
}
public static IEnumerable<Bike> GetBike()
{
for (int i = 0; i < 2; i++)
{
Bike bike = new Bike();
if (i == 0)
{
bike.Manufacturer = "Harley";
bike.Model = "NightRod";
}
else
{
bike.Manufacturer = "Enfield";
bike.Model = "Bullet";
}
yield return bike;
}
}
}
public class Vehicle
{
public Vehicle()
{
}
public int NoOfWheels;
public string Manufacturer;
public string Model;
}
public class Car : Vehicle
{
public Car():base()
{
NoOfWheels = 4;
}
}
public class Bike : Vehicle
{
public Bike() : base()
{
NoOfWheels = 2;
}
}
Union does not append to an existing enumeration, instead, it returns a NEW enumeration, yielding the combined results of both.
In your first example, you are calling union and then discarding the resulting enum.
You could have done:
queries = queries.Union(GetBike());
In your first case you aren't using the result of the Union.
The code queries.Union(GetBike()); does not modify queries.
You could call it like this and get the result you're looking for:
//First case
foreach (Vehicle v in queries.Union(GetBike()))
Console.WriteLine(v.Manufacturer);
Console.ReadLine();
I tend to dislike code like queries = queries.Union(GetBike());, but that is valid.
I am trying to convert the items in a list in to a string. but every time I convert it or display it all is shows is "TwitchIrcChar.user". If some one could help with this, it would be very helpful. sorry if noob question, but im new to lists. ive tried using convert.ToString and userlist.tostring. both gave the same output
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Media;
namespace TwitchIrcChat
{
class User
{
static Random random = new Random();
public string UserName { get; set; }
public SolidColorBrush Color { get; set; }
public bool IsMod { get; set; }
public User(string username)
{
IsMod = false;
UserName = username;
randomColor();
}
public void setColor(SolidColorBrush color)
{
Color = color;
}
private void randomColor()
{
var temp = Brushes.White;
int randomColor = random.Next(0, 10);
switch (randomColor)
{
case 0:
temp = Brushes.Blue;
break;
case 1:
temp = Brushes.Green;
break;
case 2:
temp = Brushes.Red;
break;
case 3:
temp = Brushes.Purple;
break;
case 4:
temp = Brushes.Orange;
break;
case 5:
temp = Brushes.Yellow;
break;
case 6:
temp = Brushes.Gold;
break;
case 7:
temp = Brushes.Teal;
break;
case 8:
temp = Brushes.Cyan;
break;
case 9:
temp = Brushes.LightBlue;
break;
case 10:
temp = Brushes.Pink;
break;
}
Color = temp;
}
}
class UserList
{
public moderation q = new moderation();
public List<User> userList { get; set; }
public UserList()
{
userList = new List<User>();
}
public void Add(string userName)
{
bool isInList = false;
foreach (var item in userList)
{
if (item.UserName.Equals(userName))
{
isInList = true;
break;
}
}
if (!isInList)
{
var tempUser = new User(userName);
userList.Add(tempUser);
}
}
public void Remove(string userName)
{
int userLocation = -1;
for (int i = 0; i < userList.Count; i++)
{
if (userName.Equals(userList[i].UserName))
{
userLocation = i;
break;
}
}
try
{
userList.RemoveAt(userLocation);
}
catch (Exception)
{
}
}
public SolidColorBrush getColor(string username)
{
var temp = Brushes.White;
foreach (var item in userList)
{
if (item.UserName.Equals(username))
{
temp = item.Color;
}
}
return temp;
}
public void setColor(string username, string color)
{
if (userList.Count(s => s.UserName == username) == 0)
{
Add(username);
}
var user = userList.First(s => s.UserName == username);
var converter = new BrushConverter();
var brush = (SolidColorBrush)converter.ConvertFromString(color);
user.Color = brush;
}
public void Clear()
{
userList.Clear();
}
public void list()
{
Console.WriteLine("qweqweqweqwe");
for (int i = 0; i < userList.Count; i++) // Loop through List with for
{
Console.WriteLine(userList[i].ToString());
Console.WriteLine("qweqweqweqwe");
}
}
public void AddMod(string userName)
{
foreach (var item in userList)
{
//string a = item.ToString();
//q.writeToFile(a);
if (item.UserName.Equals(userName))
{
item.IsMod = true;
}
}
}
}
}
You could override ToString like others have suggested or if UserName is all you rally want you just do.
Console.WriteLine(userList[i].UserName.ToString());
or
Console.WriteLine(userList[i].UserName);
since its already a string
You have to override ToString() method in your class and return the desired string in that method. For instance if you want to return UserName when ToString() is called on an instance of User, you can do it like this:
public class User
{
public string UserName {get;set;}
public override string ToString()
{
return UserName;
}
}
If you don't do this, the default ToString() will return the name of the object's type.
This has nothing to do with lists, and everything to do with how you represent a custom object as a string.
The default behavior for .ToString() is exactly what you're seeing, outputting the name of the class. .NET has no way of intuitively knowing what you mean when you want to see an object as a string. You need to explicitly provide that logic by overriding .ToString() on your object.
For example, if you just want to see the user's name, it could be something as simple as:
public override string ToString()
{
return UserName;
}
Essentially, the question you need to ask yourself is, "Am I outputting a property on the User, or am I outputting the User itself?" If the latter, you'd definitely want to encapsulate that logic into a .ToString() override, since that logic may change over time. For example, if you ever want the string representation of a User to also show if the User is a "mod" (say, for example, with a * character), you would just add that in the override:
public override string ToString()
{
return string.Format("{0} {1}",
UserName,
IsMod ? "(*)" : string.Empty);
}
The default behavior of ToString() (inherited from System.Object) is to display the type name. If you want to change this behavior you must override ToString:
class User
{
...
public override string ToString()
{
return UserName + (IsMod ? " (moderator)" : "");
}
}
ToString is used automatically by Console.WriteLine, so you simply call it like this:
Console.WriteLine(userList[i]);
You can also add objects directly to listboxes for instance, as those use ToString as well in order to display the items.
listBox1.Items.Add(user);
To give some background I'm trying to solve the Project Euler Problem 54 involving poker hands. Though there's infinite approaches to this. What I would like to do is enumerate through a list of strings, for example:
{ "8C", "TS", "KC", "9H", "4S" };
I would like to "get" an instance of class card with properties value, and suit, for each respective string. I've not yet utilized get/set so maybe there is an obvious approach to this I'm missing.
Ultimately I would like to have a list of objects type Card, I don't mind building all the card's ahead of time, such that "2H" returns an instance of type Card where suit = Hearts, and value = 2, for example.
I know this code is wrong, but it should give an idea of what I'm trying to do. Any suggestions would be appreciated.
class Card
{
public string suit;
public int value;
public string cardname
{
get
{
if (cardname == "2H") Card TwoH = new Card();
TwoH.suit = "Hearts"
TwoH.value = 2;
return TwoH;
}
}
}
Why not make a constructor that fills suit and value based on a string parameter
public Card(string name)
{
switch(name)
{
case "2H":
this.suit = "Hearts";
this.value = 2;
break;
//...
}
}
This might not be the exact solution you seem to be asking for but if the values you'll be getting (eg 2H, 3C etc) are all 2 characters long, then you can try this:
public class Card
{
public string suit { get; set; }
public int value { get; set; }
public static Card GetCard(string cardName)
{
string tmpSuit;
int tmpValue;
char[] cardNameParts = cardName.ToCharArray();
switch(charNameParts[0])
{
case "A":
tmpValue = 1;
break;
case "2":
tmpValue = 2;
break;
...
}
switch(charNameParts[1])
{
case "H":
tmpSuit= "Hearts";
break;
case "C":
tmpSuit= "Clubs";
break;
...
}
return new Card() { suit = tmpSuit, value = tmpValue };
}
}
I would do it like that:
public class Card
{
public string Suit { get; set; }
public int Value { get; set; }
public static Card FromString(string s)
{
if (s == "2H") return new Card() { Suit = "Hearts", Value = 2 };
else if (s == "....")
...
else return null;
}
}
I have converted your suit and value field into properties and instead of some getter method which in your case wouldn't work I have added a static method.
You can use it like this Card card2H = Card.FromString("2H");
Maybe use two switch statements, first
switch (cardname[0])
{
...
}
then
switch (cardname[1])
{
...
}
Before that, check that cardname.Length == 2. In each switch, have a default section where you throw an exception in case the char value doesn't make sense.