Assign values to arrays on structs using a comfortable code - c#

The idea is simple. Make a struct for "Departments" of a store, give it a variable for naming (a string called "Department"), and a array to save all buys done in that department.
Now, I want that every time that I'm gonna save a buy on a specific Department, it auto-applies a discount based on department's name and buy amount.
Now, the example class:
class Program
{
struct Departments
{
public string Department;
private double[] _buys;
public double[] Buys
{
get { return _buys; }
set
{
if (value > 100)
{
if (Department == "CLOTH")
_buys = value * .95;
if (Department == "FOOD")
_buys = value * .90;
if (Department == "OTHER")
_buys = value * .97;
}
_buys = value;
}
}
}
static void Main()
{
var departments = new Departments[3];
departments[0].Department = "CLOTH";
departments[1].Department = "FOOD";
departments[2].Department = "OTHER";
departments[0].Buys = new double[5];
departments[0].Buys[0] = 105;
}
}
Note the line departments[0].Buys[0] = 105, that's the way that I want to save bought things, "Code-Simple"...
Now, note the property Buys of the struct, it's an "Array Property". Then, when I use the value > 100 condition it gives an obvious error, can't cast from double to double[].
The question... how can I write a right condition for value > 100, what else must be put on the stuct to achieve this?
I've tried with "Indexers", but as long as I've tried I can't make it take assignemts via departments[0].Buys[0] = 105 in the right way.
Please note that I wanna keep this schema, specially for the facility of simply say departments[0].Buys[0] = 105 to asing buyings
EDIT:
The previous struct "Departments" is done for example-purposes only. I won't answers about making it by another way to have right "Departments", I want an answer of how to make the set parameter work on individual elements of arrays

One more potential solution is to make another class for the _buys array:
class Buys
{
private double[] _buys;
public Buys (int capacity)
{
_buys = new double[capacity];
}
public double this[int index]
{
get { return _buys; }
set
{
if (value > 100)
{
if (Department == "CLOTH")
value = value * .95;
if (Department == "FOOD")
value = value * .90;
if (Department == "OTHER")
value = value * .97;
}
_buys = value;
}
}
}
struct Departments
{
public string Department;
public Buys Buys;
}
static void Main()
{
var departments = new Departments[3];
departments[0].Department = "CLOTH";
departments[1].Department = "FOOD";
departments[2].Department = "OTHER";
departments[0].Buys = new Buys(5);
departments[0].Buys[0] = 105;
}

You'd be better off using a List<double> to record the purchases. That way the list can grow dynamically. You can also use indexes to get the list elements.
You can simplify the discount code using a dictionary.
For this data you'd also be better off using a class, rather than a struct. Structs are generally better used for immutable values. Make the class represent a single department and store the appropriate discount in it.
So something like this:
class Program
{
class Department
{
public string Name;
public double Discount;
private List<double> _buys = new List<double>();
public List<double> Buys
{
get { return _buys; }
}
public void AddBuy(double value)
{
_buys.Add(value > 100 ? value * discount : value);
}
}
static void Main()
{
var departments = new List<Department>();
departments.Add(new Department { Name = "CLOTH", Discount = 0.95 });
departments.Add(new Department { Name = "FOOD", Discount = 0.90 });
departments.Add(new Department { Name = "OTHER", Discount = 0.97 });
departments[0].AddBuy(105);
Console.WriteLine(departments[0].Buys[0]);
}
}
There are many other ways I'd improve this design, but this should get you going.

you could do something like this
public class Departments
{
public string Department;
public MyList buys;
public Departments()
{
buys = new MyList(this, 5);
}
}
public class MyList
{
private double[] backingList;
private Departments owner;
public MyList(Departments owner, int size)
{
this.owner = owner;
backingList = new T[size];
}
public double this[int index]
{
get{ return backingList[index]; }
set { backingList[index] = discountFor(owner.Department) * value; }
}
private float discountFor(string department)
{
switch(department)
{
case "department1":
return 0.5f;
//...
default:
return 1.0f;
}
}
}
However you are not maintaining good separation of concerns by putting the discount into the setter its self. Better code would look something like
departments[0].Buys[0] = DiscountFor("department1") * 105;

By your error you can do something like this.
struct Departments
{
public string Department;
private double[] _buys;
public double[] Buys
{
get { return _buys; }
set
{
for (int i = 0; i < value.Length; i++)
{
if (value[i] > 100)
{
if (Department == "CLOTH")
_buys[i] = value[i] * .95; if (Department == "FOOD")
_buys[i] = value[i] * .90; if (Department == "OTHER")
_buys[i] = value[i] * .97;
}
}
_buys = value;
}
}
}

You could create a method to do the setting like this:
public double[] Buys { get; set; }
public void SetBuy(int index, double value)
{
if (value > 100)
{
if (Department == "CLOTH")
value = value * .95;
if (Department == "FOOD")
value = value * .90;
if (Department == "OTHER")
value = value * .97;
}
_buys[index] = value;
}

Structs which contain mutable references to mutable items are generally a bad idea, since such structures end up exhibiting a weird combination of value and reference semantics. For example, what should be the effect of:
Departments dep1,dep2;
...
dep1 = dep2;
dep1.Department = "CLOTH";
dep1.Buys[5] = 123;
It's hardly obvious that such a statement will or should affect dep2.Buys[5]. If a given structure's Buys field/property would always refer to the same array, such semantics might be tolerable, but what happens if the array needs to be resized?

Related

I want to ask in the if statement if the cake is baked how do I do that in single-dimensional array? I'm stuck

using System;
namespace ConsoleApp12
{
class Cake
{
private string cakeType;
private int weight;
private bool baked;
public Cake(string cakeType, int weight)
{
this.cakeType = cakeType;
this.weight = weight;
this.baked = true;
}
public Cake(string cakeType, int weight, bool baked)
{
this.cakeType = cakeType;
this.weight = weight;
this.baked = baked;
}
public Cake(int weight)
{
this.cakeType = "chocolate";
this.weight = weight;
this.baked = true;
}
public string IsBaked()
{
int count = 0;
Cake[] CakeArr = new Cake[3];
for (int i = 0; i < CakeArr.Length; i++)
{
if (/* if cake is baked */)
{
return "The Cake is indeed baked...";
}
else
{
count++;
}
}
return "There are: " + count + " not baked cakes...";
}
public string GetCakeType() { return this.cakeType; }
public int GetWeight() { return this.weight; }
public bool GetBaked() { return this.baked; }
public void SetBaked(bool baked) { this.baked = baked; }
public void Sold(int weight) { this.weight -= weight; }
}
class Program
{
static void Main(string[] args)
{
Cake c1 = new Cake(1800);
Cake c2 = new Cake("cheese", 1200, false);
Cake c3 = new Cake("chocolate", 2100, true);
c1.Sold(400);
if (c1 == c3)
Console.WriteLine("aaa");
else
Console.WriteLine("bbb");
c3.Sold(700);
if (c1 == c2 || c2 == c3)
Console.WriteLine("ccc");
else
if (c1 == c3)
Console.WriteLine("ddd");
c1.Sold(1400);
c2.SetBaked(c1.GetBaked());
if (c2.GetBaked())
Console.WriteLine("eee");
Console.WriteLine(c2.IsBaked());
}
}
}
I did everything I need but I do not know how to make the system check if the cake is baked in an if statement...
It doesnt matter what everything else do like the other methods because they all supposed to work anyways I just need to find a solution to the method IsBaked in the class Cake.
Please help, thank you.
Assuming you want to check how many of c1, c2, c3 are baked, you might want to create an extension method:
public static class MyCakeExtensionMethods{
public static string HowManyAreNotBaked(this Cake[] cakeArr ){
int count = 0;
for (int i = 0; i < cakeArr.Length; i++)
{
if (!cakeArr[i].GetBaked())
{
count++;
}
}
if( count == 0){
return "all cakes are baked";
return "There are: " + count + " not baked cakes...";
}
}
Note that the body could be mostly simplified to CakeArr.Count(c => c.GetBaked());
But there are other issues with your code:
You should probably be using properties instead of get/set methods
You should probably not allow the cake type to be changed after creation. Unless you found some way to transform a cheese-cake into a chocolatecake in the real world.
You should probably change SetBaked(bool baked) into Bake(), since you cannot un-bake a cake.
You should probably add a check to Sold to ensure you cannot sell more cake than there is.

How to deserialize an array containing a list?

I would like to deserialize an array containing some things and 3 List.
The program works fine except for List. The lists are created but they contain nothing !
Can you help me ?
Here is how the xml file looks like :
<blind>
<folder>C:\Users\Michael\Desktop\BT 1 normal\Programme BT\</folder>
<nombre_titres>25</nombre_titres>
<numero></numero>
<theme></theme>
<heure_debut></heure_debut>
<mdp>a</mdp>
<lien></lien>
<playlist>
<extrait>
<artiste>Abba</artiste>
<titre>Take a chance on me</titre>
<PointAT>1.25</PointAT>
<PointA>0.5</PointA>
<PointT>0.5</PointT>
<JoueursAT>
<joueurAT>Ahkayaqua</joueurAT>
<joueurAT>Angelene</joueurAT>
</JoueursAT>
<JoueursA>
<joueurA></joueurA>
</JoueursA>
<JoueursT>
<joueurT></joueurT>
</JoueursT>
</extrait>
<extrait>
....
</extrait>
</playlist>
</blind>
My code to deserialize :
XElement xmle;
xmle = XElement.Load(_folder + "Blind.xml");
textBox1.Text = xmle.Element("numero").Value;
textBox4.Text = xmle.Element("theme").Value;
textBox3.Text = xmle.Element("heure_debut").Value;
textBox5.Text = xmle.Element("lien").Value;
textBox2.Text = xmle.Element("mdp").Value;
extraits = (from ex in xmle.Element("playlist").Elements("extrait")
select new Extrait
(ex.Element("artiste").Value,
ex.Element("titre").Value,
0,
0,
0,
(from jat in ex.Element("JoueursAT").Elements("JoueurAT")
select jat.Element("JoueurAT").Value).ToList(),
(from ja in ex.Element("JoueursA").Elements("JoueurA")
select ja.Element("JoueurA").Value).ToList(),
(from jt in ex.Element("JoueursT").Elements("JoueurT")
select jt.Element("JoueurT").Value).ToList())).ToArray();
And here is my class:
public class Extrait
{
private String _Artiste;
private String _Titre;
private double _PointA;
private double _PointT;
private double _PointAT;
private List<String> _JoueurA;
private List<String> _JoueurT;
private List<String> _JoueurAT;
public String Artiste
{
get { return _Artiste; }
set { _Artiste = value; }
}
public String Titre
{
get { return _Titre; }
set { _Titre = value; }
}
public Double PointA
{
get { return _PointA; }
set { _PointA = value; }
}
public Double PointT
{
get { return _PointT; }
set { _PointT = value; }
}
public Double PointAT
{
get { return _PointAT; }
set { _PointAT = value; }
}
public List<String> JoueurA
{
get { return _JoueurA; }
set { _JoueurA = value; }
}
public List<String> JoueurT
{
get { return _JoueurT; }
set { _JoueurT = value; }
}
public List<String> JoueurAT
{
get { return _JoueurAT; }
set { _JoueurAT = value; }
}
public Extrait(String Artiste, String Titre, Double PointA, Double PointT, Double PointAT, List<String> JoueurAT, List<String> JoueurA, List<String> JoueurT)
{
_Artiste = Artiste;
_Titre = Titre;
_PointA = PointA;
_PointT = PointT;
_PointAT = PointAT;
_JoueurAT = JoueurAT;
_JoueurA = JoueurA;
_JoueurT = JoueurT;
}
}
Well, I've tried many possibilities, but none worked !
If this is your actual xml, then look at the inner tags - they start with lower letter. Your xml have <joueurAT> while you selecting elements with name .Elements("JoueurAT") - node names are case-sensitive.
Your code should look like:
extraits = (from ex in xmle.Element("playlist").Elements("extrait")
select new Extrait
(ex.Element("artiste").Value,
ex.Element("titre").Value,
0,
0,
0,
(from jat in ex.Element("JoueursAT").Elements("joueurAT")
select jat.Value).ToList(),
(from ja in ex.Element("JoueursA").Elements("joueurA")
select ja.Value).ToList(),
(from jt in ex.Element("JoueursT").Elements("joueurT")
select jt.Value).ToList())).ToArray();
This should fix it. Basically the default behaviour is to use two-level nesting for lists (meaning it defaults to [XmlArray] plus [XmlArrayItem]; you only have one-level here, so you need to tell it.
[XmlElement]
public List<String> JoueurA
{
get { return _JoueurA; }
set { _JoueurA = value; }
}
[XmlElement]
public List<String> JoueurT
{
get { return _JoueurT; }
set { _JoueurT = value; }
}
[XmlElement]
public List<String> JoueurAT
{
get { return _JoueurAT; }
set { _JoueurAT = value; }
}
Btw; you might find it more convenient to use something like auto-properties here; an example for both regular properties and lists:
public double PointAT {get;set;}
[XmlElement]
public List<string> JoueurA {get;} = new List<string>();
This is a lot more convenient than messing with all the fields yourself.
You probably also want to make sure you have a public parameterless constructor; frankly I'd just remove the custom constructor (in which case: a public parameterless constructor is included for free), but otherwise - I'd just add:
public Extrait() {}
The change is needed in the blind class
[XmlRoot("blind")]
public class Blind
{
[XmlArray("playlist")]
[XmlArrayItem("extrait")]
public List<Extrait> extrait { get; set; }
}
public class Extrait
{
}
(from jat in ex.Element("JoueursAT").Elements("JoueurAT")
select jat.Element("JoueurAT").Value).ToList()
should become
(from jat in ex.Element("JoueursAT").Elements("joueurAT")
select jat.Value).ToList()
I'm not sure if C#'s XML library is case sensitive when it comes to token names, but when in doubt, it's better to play it safe.
You also tried to access an element "joueurAT" when making your select despite having actually looped over them already, so you can just access the Value property directly.
Also instead of using LINQ the way you do, you could try the extension methods, which tend to be more readable :
xmle.Element("playlist").Elements("extrait")
.Select(ex => new Extrait
{
Artiste = ex.Element("artiste").Value,
Titre = ex.Element("titre").Value,
PointA = 0,
PointT = 0,
PointAT = 0,
JoueurA = ex.Element("JoueursAT").Elements("joueurAT").Select(jat => jat.Value).ToList(),
JoueurT = ex.Element("JoueursA").Elements("joueurA").Select(ja => ja.Value).ToList(),
JoueurAT = ex.Element("JoueursT").Elements("joueurT").Select(jt => jt.Value).ToList()
});

If int value equal to x replace with a string

I am storing a int in schadstoffklasse so when calling the Car object like so (last int in brackets) :
PKW Kaefer = new PKW("VW", "Käfer", "K-GS-01", 1965, 9999, 1000, 30, 1);
I can either say 0, 1, 2.
Now when i write this Console.WriteLine(Kaefer.Schadstoffklasse)
to the console it obiously outputs 1 in this case.
I do want it to not say 1 i want for example....
0 = foo
1 = bar
2 = foobar
So it outputs to the console a string.
Here is what i have tried, which does not work.
private int schadstoffklasse;
public int Schadstoffklasse
{
get
{
return schadstoffklasse;
}
set
{
if (value == 0)
{
string foo = value.ToString();
foo = "BLABLALBA";
}
schadstoffklasse = value;
}
}
Thank you for having patience with a beginner
You can't have a property return mixed types. Your property of Schadstoffklasse is an int, therefore it can only ever return an int never a string.
There are a variety of different ways to accomplish this though, but without knowing more of how you are using this it'd be impossible to say which one you should do. I'd recommend either another property that has no setter and the getter looks at the other property, reads it's value and returns the string that you want or a method that does the same.
To expand on my suggestion:
public enum SchadstofklasseStrings
{
foo = 0,
bar = 1,
foobar = 2
}
public int Schadstoffklasse { get; set; }
public string SchadstoffklasseToString {
{
get
{
var stringValue = (SchadstofklasseStrings) Schadstoffklasse;
return stringValue.ToString();
}
}
Also, sorry for mutilating the German.
You can't change the type of a variable from int to string .
in this case i would create an array
["foo","bar","foobar"]
and use value of schadstoffklasse as an index
Console.WriteLine(Kaefer.myArray[Schadstoffklasse]);
Try this
private int schadstoffklasse;
public object Schadstoffklasse
{
get
{
if(this.schadstoffklasse==0)
return "foo";
if(this.schadstoffklasse==1)
return "bar";
if(this.schadstoffklasse==2)
return "foobar";
return "N/A";
}
set
{
this.schadstoffklasse=(int)value;
}
}
Note: The explain from user #gilliduck is useful. Consider this just
as a situational workaround.
I find enum helpful in situations like this since it is a collection of named integers. This is one example of how I might handle it.
void Main()
{
var Kaefer = new PKW("VW", "Käfer", "K-GS-01", 1965, 9999, 1000, 30, Schadstoffklassen.Bar);
Console.WriteLine(Enum.GetName(typeof(Schadstoffklassen), Kaefer.Schadstoffklasse));
// Output: Bar
}
public class PKW
{
private Schadstoffklassen schadstoffklasse;
public PKW(string v1, string v2, string v3, int v4, int v5, int v6, int v7, Schadstoffklassen _schadstoffklasse) {
schadstoffklasse = _schadstoffklasse;
}
public Schadstoffklassen Schadstoffklasse
{
get { return schadstoffklasse; }
set { schadstoffklasse = value; }
}
}
public enum Schadstoffklassen {
Foo = 0,
Bar = 1,
FooBar = 2
}

Can't figure out why Object reference is null

Working on a program for class, and am about 95% complete, but have run into a roadblock. I've got a Flight class that holds information about the flight, as well as a seating chart. Using a windows form listbox to select from the flight objects I created by reading from a text file. I can get values for every property from the class object, except for one, SeatChart.
Here's the pertinent code in the main program:
private void lstFlights_SelectedIndexChanged(object sender, EventArgs e)
{
curFlight = (Flight)lstFlights.SelectedItem;
DisplayNewFlightChart();
}
private void DisplayNewFlightChart()
{
int seats = curFlight.Rows * curFlight.Seats;
lstSeatingChart.Items.Clear();
string[] seatChart = curFlight.SeatChart;
for (int x = 0; x <= seats; x++)
{
lstSeatingChart.Items.Add("Seat " + (x + 1) + " " + seatChart[x]);
}
}
And here is the code from the class:
class Flight
{
private string mPlane;
private string mDepartureTime;
private string mDestination;
private int mRows;
private int mSeats;
private string[] mSeatChart;
public Flight()
{
}
// Create the overloaded Constructor
public Flight(string planeType, string departureTime,
string destination, int numRows,
int numSeatsPerRow)
{
this.Plane = planeType;
this.DepartureTime = departureTime;
this.Destination = destination;
this.Rows = numRows;
this.Seats = numSeatsPerRow;
this.SeatChart = mSeatChart;
mSeatChart = new string[Rows * Seats];
for (int seat = 0; seat <= mSeatChart.GetUpperBound(0); seat++)
{
mSeatChart[seat] = "Open";
}
}
public string Plane
{
get { return mPlane; }
set { mPlane = value; }
}
public string DepartureTime
{
get { return mDepartureTime; }
set { mDepartureTime = value; }
}
public string Destination
{
get { return mDestination; }
set { mDestination = value; }
}
public int Rows
{
get { return mRows; }
set { mRows = value; }
}
public int Seats
{
get { return mSeats; }
set { mSeats = value; }
}
public string[] SeatChart
{
get { return mSeatChart; }
set { mSeatChart = value; }
}
public void MakeReservation(string passName, int seat)
{
bool seatTaken = false;
if (mSeatChart[seat] != "Open") seatTaken = true;
if (passName != "" && seatTaken == false)
{
mSeatChart[seat] = passName;
}
else
{
MessageBox.Show("Please Enter a Passenger Name, in an unreserved seat");
}
}
It's telling me the curFlight.SeatChart is null, even though I can pull .Rows and .Seats from the curFlight just fine. I have no clue why .SeatChart is messing up. lstFlights is the list of flight objects pulled from the text file, and lstSeatingChart is where I want to display a list of seats.
You are setting SeatChart to mSeatChart, which is null at that time. So no reference to an object is made for this.SeatChart.
After that you initialize mSeatChart and fill it.
You should move setting this.SeatChart after initializing mSeatChart.
mSeatChart = new string[Rows * Seats];
this.SeatChart = mSeatChart;
Edit:
In addition, SeatChart is the property and mSeatChart is the member variable. SeatChart will be used to expose mSeatChart, so it's really weird to set SeatChart with mSeatChart. So weird that I didn't even think you were doing that.
So in your case leave the following out in the constructor:
this.SeatChart = mSeatChart;
I think the actual cause of your issue is somewhere else in the code, where you initiate Flight and fill the list. If I understand correctly you get a null reference error on the concatenation in the for loop?
string[] seatChart = curFlight.SeatChart;
for (int x = 0; x <= seats; x++)
{
lstSeatingChart.Items.Add("Seat " + (x + 1) + " " + seatChart[x]);
}
Check where you initate each Flight object. I bet you are using the empty constructor: new Flight()
Remove the empty constructor, because you don't expect empty values apparently. And if you really need the empty constructor then either initiate all member variables as expected or perform a null check wherever you want to use them.
And once you found the cause, make sure you change the for loop to
for (int x = 0; x < seats; x++)
since you are checking for the number of seats and do a zero-based loop. If x = seats you would have performed the loop seats + 1 times (rows*seats + 1).
If your code relies on a particular property never being null, you need to make sure it is initialized in all constructors.
Based on the logic of your class, I would suggest you shouldn't have a parameter less constructor. It doesn't make sense to have a flight that didn't have a known number of seats (in your implementation at least).
Also some style things.
You don't need to declare your private instance variables. Just use
public string destination {get; set;}
Declare "open" as a class constant and use that constant rather than the hard coded string value.

how can i get an access to the elements of array in the class

I have a problem which I don't know how to solve. I have a class. This class has two arrays. I would like to get access via properties. How can I do it? I tried to use indexers, but it is possible if I have only one array. Here what I want to do:
public class pointCollection
{
string[] myX;
double[] myY;
int maxArray;
int i;
public pointCollection(int maxArray)
{
this.maxArray = maxArray;
this.myX = new string[maxArray];
this.myY = new double[maxArray];
}
public string X //It is just simple variable
{
set { this.myX[i] = value; }
get { return this.myX[i]; }
}
public double Y //it's too
{
set { this.myY[i] = value; }
get { return this.myY[i]; }
}
}
With this code, my X and Y are only simple variables, but not arrays.
If I use indexers, I get access only to one array:
public string this[int i]
{
set { this.myX[i] = value; }
get { return this.myX[i]; }
}
But how can I get access to second array?
Or I can't use property in this case? And I need only use:
public string[] myX;
public double[] myY;
An example with Tuples.
public class pointCollection
{
Tuple<String,Double>[] myPoints;
int maxArray;
int i;
public pointCollection(int maxArray)
{
this.maxArray = maxArray;
this.myPoints = new Tuple<String,Double>[maxArray];
}
public Tuple<String,Double> this[int i]
{
set { this.myPoints[i] = value; }
get { return this.myPoints[i]; }
}
}
And to access the points you do...
pointCollection pc = new pointCollection(10);
// add some data
String x = pc[4].Item1; // the first entry in a tuple is accessed via the Item1 property
Double y = pc[4].Item2; // the second entry in a tuple is accessed via the Item2 property
If I got it right, you need some kind or read/write-only wrapper for arrays to be exposed as properties.
public class ReadWriteOnlyArray<T>{
private T[] _array;
public ReadWriteOnlyArray(T[] array){
this._array = array;
}
public T this[int i]{
get { return _array[i]; }
set { _array[i] = value; }
}
}
public class pointCollection
{
string[] myX;
double[] myY;
int maxArray;
public ReadWriteOnlyArray<string> X {get; private set;}
public ReadWriteOnlyArray<double> Y {get; private set;}
public pointCollection(int maxArray)
{
this.maxArray = maxArray;
this.myX = new string[maxArray];
this.myY = new double[maxArray];
X = new ReadWriteOnlyArray<string>(myX);
Y = new ReadWriteOnlyArray<double>(myY);
}
}
and usage
var c = new pointCollection(100);
c.X[10] = "hello world";
c.Y[20] = c.Y[30] + c.Y[40];
The closest you'll come without either changing your data structure or moving to methods is to make a property that returns each array, much like you did in your first code block, except without the [i].
Then, you do var x = instanceOfPointCollection.MyX[someI]; for example.

Categories