I'm studying programming right now and I had to create a snake game.
In the game, there are around 5 possible consumables for the snake and I decided to put every new Consumable in a Consumable array.
Now I wanted to iterate with foreach loops through the array and do something like:
foreach (Apple apple in consumables)
{
renderer.DrawApple(apple);
}
However when there are different objects in the array like an Apple and a SegmentRemover (which is possible, because they inherit from the Consumable class), then the compiler iterates over the SegmentRemover as well and I get an invalid cast exception.
I thought since I'm declaring in the foreach loop that I only want to iterate over Apple objects, that it should work.
Are there any easy ways to get around this? Preferably without things like var or typeof, since I'm not allowed to use these yet.
What you actually want is only those items that are "castable" to the type of Apple. For that use OfType<Apple> (uses linq):
foreach (Apple apple in consumables.OfType<Apple>())
{
renderer.DrawApple(apple);
}
A non linq solution which will do pretty much the same is to use the as operator:
foreach(var item in consumbles)
{
var apple = item as Apple;
if(apple != null)
{
renderer.DrawApple(apple);
}
}
However IMO if all these items are placed in the same list, and as they all inherit from Consumble already, a better design all together, using polymorphisem, is to define for each type of Consumable a draw method as #dasblinkenlight suggested. And have specific implementations for each type. In the case of SegmentRemover it might be an empty implementation and in the Apple it might call the renderer.
You could flip the logic around, letting each consumable draw itself in a renderer:
interface IConsumable {
void draw(Renderer renderer);
}
class Apple : IConsumable {
void draw(Renderer renderer) {
renderer.DrawApple(this);
}
}
class SegmentRemover : IConsumable {
void draw(Renderer renderer) {
renderer.DrawSegmentRemover(this);
}
}
Now your loop can go like this:
foreach (IConsumable consumable in consumables) {
consumable.Draw(renderer);
}
This way you invoke Draw polymorphically on each instance of IConsumable, so the code that gets executed is decided at runtime by the actual class implementing IConsumable interface.
Your consumables is collection, are you trying to get to the collection with an instance of the object that stores the collection? if yes:
Try:
foreach (Apple apple in consumables.consumables)
{
renderer.DrawApple(apple);
}
Related
I am attempting to iterate through the members of a list which implement a particular interface, called ImplementsGraphics and then call the method GetModels and add the return result to a list.
However, whenever I attempt to iterate through my objects, and perform the casting operation, I appear to be overwriting the same reference during my iteration. I have deduced that my problem is something to do with where, when and how I am instantiating my variables, but I can not decipher exactly what the intended behavior is.
I've tried numerous permutations of the following code:
public List<Model> GetModels()
{
var models = new List<Model>();
foreach (Actor actor in registeredActors.Where(n=>n is ImplementsGraphics))
{
var graphicActor = (ImplementsGraphics)actor;
models.AddRange(graphicActor.GetModels());
}
return models;
}
The problem line is var graphicActor = (ImplementsGraphics)actor; but I don't know how to write it such that declaring graphicsActor does not overwrite the existing instances of it stored in models.
Before my first several rounds of troubleshooting, I had
public List<Model> GetModels()
{
var models = new List<Model>();
foreach (Actor actor in registeredActors)
{
if((ImplementsGraphics)actor != null)
models.AddRange(((ImplementsGraphics)actor).GetModels());
}
return models;
}
Which I expected to work, as I had thought actor was safe across iteration, but apparently not.
Desired Behavior:
Return a list, which is all the return results of GetModels() for ever Actor in RegisteredActors which implements ImplementsGraphics
Actual Behavior:
Returns a list, which is the same return value repeated for each Actor in Registered Actor, which implements ImplementsGraphics.
EDIT:
In the class StaticActor which is a child of Actor and implements ImplementsGraphics its defined as follows:
public List<Model> GetModels()
{
foreach (ModelMesh mesh in model.Meshes)
{
foreach (BasicEffect effect in mesh.Effects)
{
effect.World = this.Transform.WorldMatrix;
}
}
return new List<Model> { Model };
}
Additonally, I have tried two other approaches which also failed. A for loop, which itereated through all of RegisteredActors, and checked if they implemented ImplementsGraphics, explicitly calling them by their index within RegisteredActors
And a LINQ query, which went
var models = RegisteredActors.Where(n=>n is ImplementsGraphics).SelectMany(n=>((ImplementsGraphics)n).GetModels())
EDIT 2:
The deinfitions of my classes are largely irrelevant, if you want a reproducable example of the behaviour I'm having trouble with, here is a far simpler example.
class MyClass
{
MyOtherClass foo = new MyOtherClass();
int bar = 0;
MyOtherClass GetOtherClass()
{
foo.bar = bar;
return foo;
}
}
class MyOtherClass
{
int bar = 0;
}
List<MyClass> MyCollection = new List<MyClass> {new MyClass(bar = 1), new MyClass(bar = 2), new Myclass(bar = 3)};
List<MyOtherClass> MyOtherCollection = new List<MyOtherClass>();
foreach(MyClass member in MyCollection)
{
MyOtherCollection.Add(member.GetOtherClass());
}
If you were to execute the above code, I expect that the value of MyOtherCollection's bar properties would be: 1, 2, 3
However, the actual result is that:
During the first iteration the values are 1
During the second iteration the values are 2, 2
During the third iteration the values are 3, 3, 3
I would appear, since none of the provided code states, only implies, that you are attempting to reuse a reference to single Model instance to draw multiple objects. Then you are adding multiple references of the same instance to the List.
The solution may be as simple as removing the static modifier from all Model variables and/or container objects.
Normally, the solution would be to create a Deep Copy of the object when it is added to the List, however, it is not directly possible to do this in XNA *1. (not that you would want to)
It would be better to allow each Actor, or StaticActor, object to directly pass its own Model(s) through the GetModels() method in the interface implementation, instead of using the additional class MyOtherClass.
*1. XNA does not expose a public constructor for the Model class. It is possible to do this using reflection. In MonoGame, there is a public Constructor available.
I tend to split my derived Classes and subsequent Lists based on properties like "StaticCollidables","DrawableStaticCollidables" and "DrawableMovingCollidables"...
This technique may require more upfront coding(and therefore is not as "elegant"), but, it is more efficient in terms of memory overhead(8 bytes + (4(32 bit) or 8(64 bit) bytes depending on sizeof(Object)) per List) and CPU overhead(no casting or is).
If you are attempting to reuse the same model, but place it in different locations, use the DrawInstancedPrimitives method using the VertexBuffers contained within each Mesh of the model.
Please comment on which of the above solutions worked for you(if any). If I have missed something please let me know, so I can correct the answer.
I have an array of Items:
Item[] ItemsOut;
The problem is I have some derived types Item, like EquipItem. They are in this array too.
I have an AddItem function for both of the Item and EquipItem classes.
Inventory.AddItem(AllRecipes.Recipes[curPage].ItemsOut[i]......);
The idea is that in case my array is of type Item[] so it is always adding Items like normal Item.
My current solution is working and it's:
if (AllRecipes.Recipes[curPage].ItemsOut[i].GetType() == typeof(EquipItem))
{
Inventory.AddItem((EquipItem)AllRecipes.Recipes[curPage].ItemsOut[i], AllRecipes.Recipes[curPage].ItemsOut[i].number);
}
else
{
Inventory.AddItem(AllRecipes.Recipes[curPage].ItemsOut[i], AllRecipes.Recipes[curPage].ItemsOut[i].number);
}
But if I have 100500 child classes I will be forced to do 100500 if statements.
How to make this automatic? Something like:
Inventory.AddItem((AllRecipes.Recipes[curPage].ItemsOut[i].GetType())AllRecipes.Recipes[curPage].ItemsOut[i], AllRecipes.Recipes[curPage].ItemsOut[i].number);
or
Inventory.AddItem(AllRecipes.Recipes[curPage].ItemsOut[i] as AllRecipes.Recipes[curPage].ItemsOut[i].GetType(), AllRecipes.Recipes[curPage].ItemsOut[i].number);
I would like to be able to do something like:
Type t = AllRecipes.Recipes[curPage].ItemsOut[i].GetType();
Inventory.AddItem((t)AllRecipes.Recipes[curPage].ItemsOut[i].number);
But it causes a "variable used as a type" error, when I DO NEED to use it as a type. Not variable of course, but its value.
First off, unless you have two methods named AddItem (one for Item and another for EquipItem) you don't need to cast your ItemsOut, just use
Inventory.AddItem(AllRecipes.Recipes[curPage].ItemsOut[i], AllRecipes.Recipes[curPage].ItemsOut[i].number);
Second, you can't do this:
Type t = AllRecipes.Recipes[curPage].ItemsOut[i].GetType();
addItem((t)AllRecipes.Recipes[curPage].ItemsOut[i]
because t is an instance of the class Type, you can only cast using the type name like (EquipItem) AllRecipes.Recipes[curPage].ItemsOut[i]
And finally, unless you are having performance issues, don't ever try to optimize your code. Doing so is what we call Premature Optimization
So, check if you have a method AddItem(EquipItem equipItem). If you don't, you don't need to check it's type and cast the Item to EquipItem. Hope I could help you.
EDIT the best thing I can think that can improve your code is clearing it a bit, like this:
var item = AllRecipes.Recipes[curPage].ItemsOut[i];
if (item is EquipItem)
{
Inventory.AddItem((EquipItem) item, item.number);
}
else
{
Inventory.AddItem(item, item.number);
}
The idea here should be not to make anything know the difference between an Item, an EquipItem (or for that matter any old FooItem).
If they all derive from Item and the array is typed as Item[] then those subclasses can be added to the array without issue
var item = new Item();
var equip = new EquipItem(); // where EquipItem inherits from Item;
var array = new Item[]{ item,equipItem}; // no error here
If you have a single AddItem method, which adds to this array and performs some action based on the type, again the calling code should not know anything about the type - perhaps some virtual method which does some action when added to the list
public class Item
{
public virtual void AddedToList(){}
}
public class EquipItem
{
public override void AddedToList()
{
// behaviour specific to EquipItem
}
}
Hi unfortunately I do not have the according link anymore but I recently read some c# cheat sheets. One of them said that one shall not remove objects from lists while iterating with for or foreach. Actually the compiler doesn't even let you remove objects from a list while iterating it in a foreach. But you can easily do that in a for-loop.
Let's say I have an Interface IEnemy which has a method that returns a boolean.
public interface IEnemy
{
bool IsDead();
}
In some other class I have a list List<IEnemy> enemies;. Now this is how I would remove all enemies from the list which are dead:
public void RemoveDead(List<IEnemy> enemies)
{
for (int i = 0; i < enemies.Count;i++ )
{
if(enemies[i].IsDead() == true)
{
enemies.Remove(enemies[i]);
}
}
}
But as this cheat sheet stated this is bad practice. So how would one do that correctly? I gues this could be done with some LINQ-statement, Lambda expression? And is this even true that this should not be done in for-loops?
Use List<T>.RemoveAll method
enemies.RemoveAll(enemy => enemy.IsDead());
I have a simple static inventory class which is a list of custom class Item. I am working on a crafting system and when I craft something I need to remove the required Items from my inventory list.
I tried to create a method that I can call which takes an array of the items to remove as a parameter, but its not working.
I think its because the foreach loop doesn't know which items to remove? I am not getting an error messages, it just doesn't work. How can I accomplish this?
public class PlayerInventory: MonoBehaviour
{
public Texture2D tempIcon;
private static List<Item> _inventory=new List<Item>();
public static List<Item> Inventory
{
get { return _inventory; }
}
public static void RemoveCraftedMaterialsFromInventory(Item[] items)
{
foreach(Item item in items)
{
PlayerInventory._inventory.Remove(item);
}
}
}
Here is the function that shows what items will be removed:
public static Item[] BowAndArrowReqs()
{
Item requiredItem1 = ObjectGenerator.CreateItem(CraftingMatType.BasicWood);
Item requiredItem2 = ObjectGenerator.CreateItem(CraftingMatType.BasicWood);
Item requiredItem3 = ObjectGenerator.CreateItem(CraftingMatType.String);
Item[] arrowRequiredItems = new Item[]{requiredItem1, requiredItem2, requiredItem3};
return arrowRequiredItems;
}
And here is where that is called:
THis is within the RecipeCheck static class:
PlayerInventory.RemoveCraftedMaterialsFromInventory(RecipeCheck.BowAndArrowReqs());
While I like Jame's answer (and it sufficiently covers the contracts), I will talk on how one might implement this equality and make several observations.
For starts, in the list returned there may be multiple objects of the same type - e.g. BasicWood, String. Then there needs to be a discriminator used for each new object.
It would be bad if RemoveCraftedMaterialsFromInventory(new [] { aWoodBlock }) to remove a Wood piece in the same way that two wood pieces were checked ("equals") to each other. This is because being "compatible for crafting" isn't necessarily the same as "being equals".
One simple approach is to assign a unique ID (see Guid.NewGuid) for each specific object. This field would be used (and it could be used exclusively) in the Equals method - however, now we're back at the initial problem, where each new object is different from any other!
So, what's the solution? Make sure to use equivalent (or identical objects) when removing them!
List<Item> items = new List<Item> {
new Wood { Condition = Wood.Rotten },
new Wood { Condition = Wood.Epic },
};
// We find the EXISTING objects that we already have ..
var woodToBurn = items.OfType<Wood>
.Where(w => w.Condition == Wood.Rotten);
// .. so we can remove them
foreach (var wood in woodToBurn) {
items.Remove(wood);
}
Well, okay, that's out of the way, but then we say: "How can we do this with a Recipe such that Equals isn't butchered and yet it will remove any items of the given type?"
Well, we can either do this by using LINQ or a List method that supports predicates (i.e. List.FindIndex) or we can implement a special Equatable to only be used in this case.
An implementation that uses a predicate might look like:
foreach (var recipeItem in recipeItems) {
// List sort of sucks; this implementation also has bad bounds
var index = items.FindIndex((item) => {
return recipeItem.MaterialType == item.MaterialType;
});
if (index >= 0) {
items.RemoveAt(index);
} else {
// Missing material :(
}
}
If class Item doesn't implement IEquatable<Item> and the bool Equals(Item other) method, then by default it will use Object.Equals which checks if they are the same object. (not two objects with the same value --- the same object).
Since you don't say how Item is implemented, I can't suggest how to write it's Equals(), however, you should also override GetHashCode() so that two Items that are Equal return the same hash code.
UPDATE (based on comments):
Essentially, List.Remove works like this:
foreach(var t in theList)
{
if (t.Equals(itemToBeRemove))
PerformSomeMagicToRemove(t);
}
So, you don't have to do anything to the code you've given in your question. Just add the Equals() method to Item.
I have an Array of an interface named iBlocks which contains objects of more than a single class(that all implement the iBlocks interface). I'm wondering if it is possible, or how else to handle the situation in which i need to call methods not covered by the interface for all objects of a certain class within this array.
For example:
iBlocks = new iBlocks[1];
iBlocks[0] = new greenBlock();
iBlocks[1] = new yellowBlock();
foreach (greenBlock in iBlocks)
{
greenBlock.doStuff()
}
Where doStuff() is a method not defined in the interface, as it has no use in the yellowBlock class. The actual interface works brilliantly as greenBlock and yellowBlock have tons of common features. However, there are special aspects of each class i would like to still access without creating an entirely separate array for each object type.
Thanks in advance!
You can use the as operator.
foreach (var block in iBlocks)
{
var green = block as greenBlock;
if (green != null)
green.doStuff()
}
Or in LINQ
foreach (var green in iBlocks.OfType<greenBlock>())
{
green.doStuff()
}