For my program, I created a new class called FinishedPiece with a number of public variables available to my main program. For example:
class FinishedPiece
{
private double _PieceLength;
public double PieceLength
{
get { return _PieceLength; }
set { _PieceLength = value; }
}
}
This all works fine, because then I can declare a new FinishedPiece and add properties:
FinishedPiece piece = new FinishedPiece();
piece.PieceLength = 48.25;
My question is, how do the same with an enum? If I do
public enum Cut
{
Angle = 0,
Straight = 1,
AngleThenStraight = 2,
StraightThenAngle = 3
};
then I'd like to change it something like this: piece.Cut = Cut.Angle; but I can only change it by declaring a new FinishedPiece.Cut object:
FinishedPiece.Cut cut = new FinishedPiece.Cut();
cut = FinishedPiece.Cut.Angle;
How do I make an enum available inside a variable so I can do piece.Cut = Cut.Angle? To me it would make sense to do something like this, but it doesn't appear to work.
public int Cut
{
get { return _Cut; }
set { _Cut = value; }
}
private enum _Cut
{
Angle = 0,
Straight = 1,
AngleThenStraight = 2,
StraightThenAngle = 3
};
Thanks in advance! Let me know if my question is unclear and I'll try to help as best as I can.
How do I make an enum available inside a variable so I can do
piece.Cut = Cut.Angle?
Just define another property of type Cut in your class like:
public Cut Cut { get; set; }
Then you can do:
FinishedPiece piece = new FinishedPiece();
piece.PieceLength = 48.25;
piece.Cut = Cut.Angle; //like this
So your class would like like:
class FinishedPiece
{
private double _PieceLength;
public double PieceLength
{
get { return _PieceLength; }
set { _PieceLength = value; }
}
public Cut Cut { get; set; }
}
Consider using Auto-Implemented properties, if you have only simple set and get
Like this:
class FinishedPiece
{
private double _PieceLength;
public double PieceLength
{
get { return _PieceLength; }
set { _PieceLength = value; }
}
private Cut _Cut;
public Cut Cut
{
get { return _Cut; }
set { _Cut = value; }
}
}
public enum Cut
{
Angle = 0,
Straight = 1,
AngleThenStraight = 2,
StraightThenAngle = 3
};
Then you can do:
var piece = new FinishedPiece();
piece.Cut = Cut.AngleThenStraight;
You can try this:
private enum Cut
{
//if you dont want to use any of these values as defaults
//just add another value and in your class private member
//assign it like for example a value called None
Angle = 0,
Straight = 1,
AngleThenStraight = 2,
StraightThenAngle = 3
};
public class FinishedPiece
{
//give it a default,if like stated in the enum you dont want
//any of those values create a None and place it here as default.
private Cut cutObj = Cut.Angle;
public Cut CutObj
{
get { return cutObj; }
set { cutObj = value; }
}
}
Then in your calling code...
FinishedPiece piece = new FinishedPiece();
//if you dont want the default change it...
piece.CutObj = Cut.Straight;
Related
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()
});
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
}
I'm trying to edit an enum value in a class instance based on whether that instance appears in a dictionary of type <string, myClass>. What seems logical to me is to do the code snippets below:
if (pumpDict.ContainsKey(ID))
{
foreach(KeyValuePair<string, PumpItem> kvp in pumpDict)
{
if(kvp.Key == ID)
{
kvp.Value.state = kvp.Value.state.Available; //error here
kvp.Value.fuelPumped = fuelPumped;
kvp.Value.fuelCost = fuelCost;
break;
}
}
}
else
{
PumpItem pump = new PumpItem();
pumpDict.Add(ID, pump);
}
And my PumpItems class is such:
namespace PoSClientWPF
{
public enum pumpState
{
Available,
customerWaiting,
Pumping,
customerPaying
};
public enum fuelSelection
{
Petrol,
Diesel,
LPG,
Hydrogen,
None
};
class PumpItem
{
public double fuelPumped;
public double fuelCost;
public fuelSelection selection;
public pumpState state;
public PumpItem()//intialize constructor
{
this.fuelPumped = 0;
this.fuelCost = 0;
this.selection = fuelSelection.None;
this.state = pumpState.Available;
}
}
}
I was led to believe that to have an enum value in a constructor, they have to be set up as above, with a new instance of those enums declared in the class body.
It seems to me, that what I'm trying to do is logical but I am getting an error on the right hand side of the assignation which states:
"member PoSClientWPF.pumpState.Available cannot be accessed with an instance reference; qualify is with a type name instead"
I've searched for this error among several forums but only seem to find errors involving calling static variables incorrectly. Can anyone point me in the direction of a solution?
Thanks in advance.
You are incorrectly accessing the Enum member:
// this is incorrect
kvp.Value.state = kvp.Value.state.Available; //error here
// this is the correct way
kvp.Value.state = PoSClientWPF.pumpState.Available;
You know you have a dictionary?
PumpItem pumpItem = pumpDict[ID];
pumpItem.state = PoSClientWPF.pumpState.Available;
or
PumpItem pumpItem;
if (pumpDict.TryGetValue(ID, out pumpItem))
{
pumpItem.state = PoSClientWPF.pumpState.Available;
}
else
{
pumpItem = new PumpItem();
pumpDict.Add(ID, pumpItem);
}
Could just add ID to PumpItem and use a List
PumpItem pumpItem = pumpList.FirstOrDefualt(x => x.ID == ID)
if (pumpItem == null)
pumpList.Add(new PumpItem(ID));
else
pumpItem.state = PoSClientWPF.pumpState.Available;
class PumpItem
{
public double fuelPumped = 0;
public double fuelCost = 0;
public fuelSelection selection = fuelSelection.None;
public pumpState state = pumpState.Available;
public Int32? ID = null;
public PumpItem()//intialize constructor
{ }
public PumpItem(Int32? ID)
{
this.ID = ID;
}
}
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.
This is minor, I know, but let's say that I have a class Character and a class Ability (mostly because that's what I'm working on). Class Character has six abilities (so typical D&D...). basically:
public class Character
{
public Character()
{
this.Str = new Ability("Strength", "Str");
this.Dex = new Ability("Dexterity", "Dex");
this.Con = new Ability("Constitution", "Con");
this.Int = new Ability("Intelligence", "Int");
this.Wis = new Ability("Wisdom", "Wis");
this.Cha = new Ability("Charisma", "Cha");
}
#region Abilities
public Ability Str { get; set; }
public Ability Dex { get; set; }
public Ability Con { get; set; }
public Ability Int { get; set; }
public Ability Wis { get; set; }
public Ability Cha { get; set; }
#endregion
}
and
public class Ability
{
public Ability()
{
Score = 10;
}
public Ability(string Name, string Abbr)
: this()
{
this.Name = Name;
this.Abbr = Abbr;
}
public string Name { get; set; }
public string Abbr { get; set; }
public int Score { get; set; }
public int Mod
{
get
{
return (Score - 10) / 2;
}
}
}
When actually using these ability properties in future code, I'd like to be able to default to just the score, like so:
//Conan hits someone
int damage = RollDice("2d6") + Conan.Str;
//evil sorcerer attack drains strength
Conan.Str = 0;
rather than:
//Conan hits someone
int damage = RollDie("2d6") + Conan.Str.Score;
//evil sorcerer attack drains strength
Conan.Str.Score = 0;
Now, the first case can be taken care of with an implicit conversion:
public static implicit operator int(Ability a)
{
return a.Score;
}
Can anybody help me with the reverse? Implicit conversion like this:
public static implicit operator Ability(int a)
{
return new Ability(){ Score = a };
}
will replace the entire attribute rather than just the score of the attribute—not the desired result...
The best you can do is increment the score by adding these methods to Ability.
public static Ability operator + (Ability lhs, int score)
{
lhs.Score += score;
return lhs;
}
public static Ability operator - (Ability lhs, int score)
{
lhs.Score -= score;
return lhs;
}
public static implicit operator int(Ability rhs)
{
return rhs.Score;
}
and using them like:
static void Main(string[] args)
{
Character evil = new Character(); //Str.Sccore=10
evil.Str += 10; //cast spell for Str.Sccore=20
evil.Str -= evil.Str; //death with Str.Sccore=0
}
First, keep your implicit conversion:
public static implicit operator Ability(int a)
{
return new Ability(){ Score = a };
}
Then in your character class: Add a private Ability attribute for str, and change the getter and the setter of the Str property as follows:
private Ability str;
public Ability Str
{
get
{
return this.str;
}
set
{
if (value.Name == "")
{
this.str.Score = value.Score;
}
else
{
this.str = value;
}
}
}
There you go :)
You could also use:
if(string.IsNullOrWhiteSpace(value.Name))
instead of
if (value.Name == "")
If you are compiling to .NET 4.0 version
EDIT: I gave you a solution that does exactly what you wanted to, but What ja72 wrote is also a good suggestion with operators + and -; you can add his solution to mine (or mine to him, whatever), it will work just fine. You will then be able to write:
Character Jax = new Character(); // Str.Score = 10
Character Conan = new Character(); // Str.Score = 10
Jax.Str = 2000; // Str.Score = 2000;
Conan.Str += 150; // Str.Score = 160
Another option is to replace the properties with delegates like this
public class Character
{
public Character()
{
...
}
#region Abilities
...
#endregion
public Func<int> Strength
{
get { return () => Str.Score; }
set { Str.Score = value(); }
}
}
and use it like this
Character evil = new Character(); //Str.Sccore=10
// fist spell hits
evil.Strength = () => 5; //set Str.Score=5
// second spell hits
evil.Strength = () => 0; //set Str.Score=5
if (evil.Strength() == 0)
{
// dead
}
Perhaps you could make Ability abstract and then derive new classes from Ability for each of the sub-classes: Strength, ...
The constructor for the Strength class would look something like this:
public Strength () : base ("Strength", "Str") { ...}
Now the ability properties off a Character would be strongly typed and the implicit conversions could turn a value like 5 into a Strength object with a value of 5. This would also prevent you from accidentally storing a Dexterity in a Strength property, for example.
[Assuming the name and abbreviations are in fact fixed for all objects of that type.]