How to check property value of object - c#

i want do some action if value of property in object is equal something.
My object:
//abstract class Tile.cs
namespace DungeonGame.Tiles
{
public abstract class Tile
{
public abstract string Type { get; set; }
}
}
//Item.cs that iherits from Tile.cs
namespace DungeonGame
{
public class Item : Tile
{
public override string Type { get; set; }
public string Name { get; set; }
public Item(string name)
{
this.Type = "item";
this.Name = name;
}
}
}
And i have several objects in public Object[,] BoardTiles { get; private set; }, I had to store different types of tiles in same place so i had to use Object type array.
What i'm trying to do is replace array index with different type of object, depending of the value of property (In this case I set value depending of object type not his value of property):
public void movefillRight(int playerPositionRowIndex, int playerPositionColumnIndex)
{
for (int r = 0; r < Rows; r++)
{
for (int c = 0; c < Cols; c++)
{
if (BoardTiles[playerPositionRowIndex, playerPositionColumnIndex ].GetType().ToString() == ("DungeonGame.Item"))
{
/* placePlayerOnTheBoard(playerPositionRowIndex, playerPositionColumnIndex, PlayerTile);
*/ BoardTiles[playerPositionRowIndex, playerPositionColumnIndex] = Item1;
BoardTiles[playerPositionRowIndex, playerPositionColumnIndex - 1] = Floor;
}
else if (BoardTiles[playerPositionRowIndex, playerPositionColumnIndex-1].GetType().ToString() == ("DungeonGame.Item"))
{
BoardTiles[playerPositionRowIndex, playerPositionColumnIndex-1] = Item1;
placePlayerOnTheBoard(playerPositionRowIndex, playerPositionColumnIndex, PlayerTile);
}
else
{
placePlayerOnTheBoard(playerPositionRowIndex, playerPositionColumnIndex, PlayerTile);
BoardTiles[playerPositionRowIndex, playerPositionColumnIndex - 1] = Floor;
}
}
}
Console.WriteLine(BoardTiles[playerPositionRowIndex, playerPositionColumnIndex].GetType().ToString());//log
}
The functionality of the function is to leave the same object on the same index when the player walks over it, so the problem is that code is ok when I have one Item, for example only sword, but when there are more items i can replace index always with same object but not with object witch different properties, when the player walks over a good sword and bad sword (same object, but another properties) he leave behind just sword... I have idea how to solve this problem but i need to refer to property value which is at specific index of my object array.

After you check that the item in the array is of a specific type you can then cast it.
if (BoardTiles[playerPositionRowIndex, playerPositionColumnIndex ].GetType().ToString() == ("DungeonGame.Item"))
{
var item = (DungeonGame.Item)BoardTiles[playerPositionRowIndex, playerPositionColumnIndex];
Console.Writeline(item.Name);
}

Related

Searching for child class properties in a list

Right now I'm creating a Quest Requirement Checker in order to find if a player is able to accomplish a mission. The type of mission that I'm working with right now is the "Have An Item In Inventory" which, as you can see, will get done if the player has one or more specified items inside his/her inventory.
Now, what is my exact problem? Well, the... items.
First of all. Item is a class with the next structure:
public int ID { get; set; }
public string Name { get; set; }
public double Price { get; set; }
public Item(int id, string name, double price)
{
ID = id;
Name = name;
Price = price;
}
And there is a class named Tool which extends the Item class:
public string Material { get; set; }
public string Classification { get; set; }
public Tool
(
int id,
string name,
double price,
string material,
string classification
) : base(id, name, price)
{
Material = material;
Classification = classification;
}
Now, this is how I create every Tool:
Items.Tool tool = new Items.Tool(1, "Shovel", 100, "Wood", "Poor");
My player object has and List of items like this one:
public List<Items.Item> InventoryItems { get; set; }
And it works as its inventory. Also, to add a new item to the list, I use this function:
player.AddItem(tool, 1);
public void AddItem(Items.Item item, int quantity)
{
for(int i = 0; i < quantity; i++)
{
InventoryItems.Add(item);
}
}
On the other hand, my current quest type "Has Items In Inventory" has a property that is, at the same time, a list of items:
public List<Items.Item> RequiredItems { get; set; }
And this is how I add items to this list:
quest.AddRequiredItem(tool, 1);
public void AddRequiredItem(Items.Item item, int quantity)
{
for(int i = 0; i < quantity; i++)
{
RequiredItems.Add(item);
}
}
In order to fulfill this quest, the player must have the same amount (or more) of items that the RequiredItems list have. So, if this quest ask the player to look around for 3 Poor Wooden Shovels, it should have at least 3 Poor Wooden Shovels on its InventoryItems list.
My quest, which is a class named HaveItemsInInventory implements the next function in order to evaluate that condition:
override public bool Accomplish()
{
bool questAccomplished = true;
foreach (var group in RequiredItems.GroupBy(x => x))
{
if (Application._player.InventoryItems.Count
(
x =>
(
x.Name == group.Key.Name &&
x.Material == group.Key.Material &&
x.Classification == group.Key.Classification
)
) < group.Count())
{
questAccomplished = false;
break;
}
}
return questAccomplished;
}
And this where all my problems appear. This two lines or code are wrong:
x.Material == group.Key.Material &&
x.Classification == group.Key.Classification
Because there's no such thing as a Material or Classification in a Item.
What i want to do is to implement different types of evaluations.
If an quest ask for a Glass of Water, I should look for properties living inside my Beberage class.
If the quest ask for just a Sword. I should look for a item with the Name "Sword" in its inventory.
If the quest ask for a Diamond Legendary Sword, well... You get my point.
Is there a way to look for these extended classes properties within my system? I can't find a way to do so.
PD: Sorry for my bad english, not a native speaker.
EDIT: I've edited my answer to address the idea of a generic task method.
If you want the task to be generic across multiple different types, you probably want to implement an IsSame or IsEquivalent method on Items.Item, and then inherit that method. You could even override the Object.Equals method (and that might be a more appropriate way).
class Item
{
public virtual bool IsSame(Item comp){ return comp.Name == Name; }
}
class Tool: Item
{
public override bool IsSame(Item comp)
{
return base.IsSame(comp) && (comp is Tool) && ((Tool)comp).Material == Material && ((Tool)comp).Classification == Classification;
}
}
Then in your accomplish iteration:
override public bool Accomplish()
{
bool questAccomplished = true;
foreach (var group in RequiredItems.GroupBy(x => x))
{
if (Application._player.InventoryItems.Count
(
x =>
(
x.IsSame(group.Key)
)
) < group.Count())
{
questAccomplished = false;
break;
}
}
return questAccomplished;
}

Assert Equal two list of objects UnitTesting c#

I'm currently doing some unit testing of a copy function and I need to compare the elements of the objects between the old list, and the newly copied list.
It works fine, but I was wondering if I can do it in a way that doesn't involve a for loop.
Here is my object:
new NaturePointObject
{
SId = 1,
Name = "Test",
Category = NaturePointCategory.Category1,
CreatorType = CreatorTypeEnum.1,
NaturR = NaturR.Bn,
Description = "Test",
Kumulation = Kumulation.EnEjendom,
Id = 1
}
My old list contains "NaturePointObject" and is called naturPointList, and it will be copied to a list called newNaturePointList.
Here is how I Assert to know if it copied succesfully:
Assert.AreEqual(naturPointList.Count,newNaturePointList.Count);
for (var i = 0; i < newNatureList.Count; i++)
{
Assert.AreEqual(naturPointList[i].Category, newNaturePointList[i].Category);
Assert.AreEqual(naturPointList[i].Description, newNaturePointList[i].Description);
Assert.AreEqual(naturPointList[i].Kumulation, newNaturePointList[i].Kumulation);
Assert.AreEqual(naturPointList[i].Name, newNaturePointList[i].Name);
Assert.AreEqual(naturPointList[i].CreatorType, newNaturePointList[i].CreatorType);
Assert.AreEqual(naturPointList[i].NaturR, newNaturePointList[i].NaturR);
Assert.AreNotEqual(naturPointList[i].SId, newNaturePointList[i].SId);
}
As you can see not all elements of the object must be equal. And I don't care about the "Id" of the object.
Is there a shorter way to do this, than run a for loop?
Probably you want to use CollectionAssert:
CollectionAssert.AreEqual(naturPointList, newNaturePointList, NaturePointObject.CategoryCreatorTypeComparer);
The only thing you need to take in mind is that you need to implement IComparer, to use in the Assert method:
public class NaturePointObject
{
private static readonly Comparer<NaturePointObject> CategoryCreatorTypeComparerInstance = new CategoryCreatorTypeRelationalComparer();
private sealed class CategoryCreatorTypeRelationalComparer : Comparer<NaturePointObject>
{
public override int Compare(NaturePointObject x, NaturePointObject y)
{
// compare fields which makes sense
if (ReferenceEquals(x, y)) return 0;
if (ReferenceEquals(null, y)) return 1;
if (ReferenceEquals(null, x)) return -1;
var categoryComparison = string.Compare(x.Category, y.Category, StringComparison.Ordinal);
if (categoryComparison != 0) return categoryComparison;
return string.Compare(x.CreatorType, y.CreatorType, StringComparison.Ordinal);
}
}
public static Comparer<NaturePointObject> CategoryCreatorTypeComparer
{
get
{
return CategoryCreatorTypeComparerInstance;
}
}
public int SId { get; set; }
public string Category { get; set; }
//other properties
public string CreatorType { get; set; }
}
You can try
Assert.IsTrue(naturPointList.SequenceEqual(newNaturePointList));
If you want to ignore the Id, you can create other classes (without Ids).
Later edit: you could overwrite the Equals method and ignore the Id.

how to sort and display an arraylist based on points in c#

I have an array list named memberData that stores the memberID, memberName, memberPoint and some other member data. I want to sort all the members based on the memberPoint field.
Here is my code:
public void displayAllMembers()
{
int index = 1;
Console.WriteLine("ALL MEMBERS");
Console.WriteLine("No\t Member Name\t\t Member ID\t Member Point");
memberData.Sort();
foreach (object data in memberData)
{
tempMember = (Member)data;
Console.WriteLine("{0}\t\t {1} {2}\t\t {3}\t\t {4}", index, tempMember.givenName, tempMember.surName, tempMember.memberID, tempMember.memberPoint);
index++;
}
}
You have to use LINQ functions for sorting depending on sorting directions like this:
To sort in ascending order:
memberData = memberData.OrderBy(m=>m.memberPoint);
To sort in descending order :
memberData = memberData.OrderByDescending(m=>m.memberPoint);
Using LINQ
Instead of Sort() which only uses the internal Equals to compare objects in the list you simply can use LINQ for this:
var sortedByMemberPoint = memberData.OrderBy(m=>m.memberPoint);
This will sort your member data by the property provided in the OrderBy method. To sort descending use OrderByDescending() instead.
Using IComparer
Alternatively you can implement your own comparer class to compare the member data (which is quite an overhead for your simple use case). That is recommended if you want to do more complex comparison. You can have a look on MSDN for a simple sample.
Try following :
public class MemberData : IComparable<MemberData>
{
public static List<MemberData> memberData = new List<MemberData>();
public string givenName {get;set;}
public string surName {get;set;}
public string memberID { get;set;}
public string memberPoint { get; set; }
public void displayAllMembers()
{
int index = 1;
Console.WriteLine("ALL MEMBERS");
Console.WriteLine("No\t Member Name\t\t Member ID\t Member Point");
memberData.Sort();
foreach (MemberData data in memberData)
{
Console.WriteLine("{0}\t\t {1} {2}\t\t {3}\t\t {4}", index, data.givenName, data.surName, data.memberID, data.memberPoint);
index++;
}
}
public int CompareTo(MemberData other)
{
if (this.givenName != other.givenName) return this.givenName.CompareTo(other.givenName);
if (this.surName != other.surName) return this.surName.CompareTo(other.surName);
if (this.memberID != other.memberID) return this.memberID.CompareTo(other.memberID);
return this.memberPoint.CompareTo(other.memberPoint);
}
}
As #derape said, you can use also an IComparer, here you can have an example using that approach also
void Main()
{
A[] a = new A[]
{
new A
{
Point = 10,
Name="A1"
},
new A
{
Point=6,
Name="A2"
},
new A
{
Point=7,
Name="A3"
}
};
Array.Sort(a, new AComparer());
//at this point a has all element sorted
}
public class A
{
public int Point { get; set; }
public string Name { get; set;}
}
public class AComparer : IComparer<A>
{
public int Compare(A x, A y)
{
if(x.Point == y.Point)
return 0;
if(x.Point < y.Point)
return -1;
else return 1;
}
}
Hope this helps

Editing an enum in a class (member cannot be accessed with an instance reference)

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;
}
}

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