Unable to get separate references during iteration - c#

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.

Related

Should this list initializer behavior be reported as bug in the Visual Studio C# Compiler?

First of all I will say that I've changed my design and no longer need that but getting a good answer for that will still be nice
I have the following class, ListContainer, in my code (The attached codes are all mcve):
class ListContainer
{
public object ContainedList
{
get; private set;
}
public int Value
{
get; private set;
}
public ListContainer(object list, int value)
{
ContainedList = list;
Value = value;
}
}
And in some other class in my code I have a List<ListContainer> and I need each ListContainer to contain this List<ListContainer>, so I can implement it like that:
//Field in the class
List<ListContainer> mContainers = null;
//In the constructor:
mContainers = new List<ListContainer>();
mContainers.Add(new ListContainer(mContainers, SOME_CONST));
mContainers.Add(new ListContainer(mContainers, SOME_OTHER_CONST));
Than it works fine, but when I've tried to use list initializer:
//Field in the class
List<ListContainer> mContainers = null;
//In the constructor:
mContainers = new List<ListContainer>
{
new ListContainer(mContainers, SOME_CONST),
new ListContainer(mContainers, SOME_OTHER_CONST)
}
You would expect the results to be equivalent but in reality the result looks like that:
mContainers
[0] - ListContainer
ContainedList = null
Value = SOME_CONST
[1] - ListContainer
ContainedList = null
Value = SOME_OTHER_CONST
Seeing this results I've inspected the output MSIL of this C# compilation and seen the following code:
Now, this explains why the problem occurs, and I've even checked out in the CSharp Language Specification document and this is the defined behavior:
A List can be created and initialized as follows:
var contacts = new List<Contact> {
new Contact {
Name = "Chris Smith",
PhoneNumbers = { "206-555-0101", "425-882-8080" }
},
new Contact {
Name = "Bob Harris",
PhoneNumbers = { "650-555-0199" }
}
};
which has the same effect as
var __clist = new List<Contact>();
Contact __c1 = new Contact();
__c1.Name = "Chris Smith";
__c1.PhoneNumbers.Add("206-555-0101");
__c1.PhoneNumbers.Add("425-882-8080");
__clist.Add(__c1);
Contact __c2 = new Contact();
__c2.Name = "Bob Harris";
__c2.PhoneNumbers.Add("650-555-0199");
__clist.Add(__c2);
var contacts = __clist;
where __clist, __c1 and __c2 are temporary variables that are otherwise invisible and inaccessible.
So obviously this behaviour is intended. Is there a good reason everything is done on the temporary variable and not on the original one? since it seems like a wrong behaviour to me.
The reason is to avoid race conditions with concurrent threads accessing the original variable where you would add your elements. An inconsistency would appear if a thread accesses the variable while not all elements are added to it yet.
Two threads accessing the same variable would therefore get an inconsistent list, with different elements in it.
This would not come as a shock if the elements are added on different lines, but since you use an object initializer, it is normal to perceive the object as directly initialized with all its elements in it, hence the need of a temporary, invisible, variable.
Is there a good reason everything is done on the temporary List and not on the original one?
There is no original list:
var __clist = new List<Contact>();
// …
__clist.Add(__c1);
// …
__clist.Add(__c2);
var contacts = __clist;
Only one list is ever created. What you probably mean is that it’s done on a temporary variable instead of the original variable, but that has no practical effect—other than probably being easier to implement. This is especially true if you think about that collection initialization is not limited to the context of variable assignments:
SomeMethodCall(new List<int>() { 1, 2, 3 });
Since there is no reference to that list, the simplest solution to implement this is just to use a temporary variable that holds the list, and put that variable at the place of the initializer then.
What’s also important about this is that the old value is completely overwritten. So in your mContainers = new List<ListContainer>, the old value of mContainers is never being looked at for the purpose of the initializer syntax.
It’s probably a good idea to think about the collection initialization as an “atomic” operation. The list only exists (at least to you) once the whole initializer completes. So you cannot reference itself from within the initializer.
Assignments are first evaluated on the right side of the = and then the assignment takes place. So mContainers is still null.

Add to list when list type is not known until runtime

I have method which accepts an object. This object I know is a List<T> however T may vary between children of a base class at any one time when being passed into the method.
So if my base class is MonthType, and I have children called BlockMonthType and AreaMonthType the object passed in could be anyone of List<BlockMonthType> or List<AreaMonthType>.
I want to be able to add items to this object however when I cast it it seems to make a copy and the original object is not updated.
I'm doing this to cast:
var objectList = ((IEnumerable<MonthType>)graphObject.Source.Object).ToList();
Now I want to create a new item and add it to the list
// where ObjectType is a Type variable containing BlockMonthType
var newObject = (BlockMonthType)Activator.CreateInstance(graphObject.Source.ObjectType);
objectList.Add(newObject);
// and carry on the world is good
This works in so far as objectList has a newObject added. However the original variable isn't updated so when I leave the method it's back to it's original state. I know the object is a List<> when passed in as I can see it in the debugger as such.
Is there anyway I can accomplish this?
Here is a cut down version of the method I'm using it in.
public TraverseGraphResult Write(ObjectGraph graphObject)
{
var objectList = ((IEnumerable<MonthType>)graphObject.Source.Object).ToList();
var newObject = (MonthType)Activator.CreateInstance(rule.ObjectType);
newObject.Month = rule.Month;
objectList.Add(newObject);
// Other stuff as well is done but that's the crux of it
}
Hopefully this gives it more context. The method is being used to try and navigate a large object tree with many class types. I'm trying to add a new class type handler which will deal with adding and removing items from a list.
// This is being used in a recursive method to loop down a object's property tree
// .. more code here
// where properties is a List<PropertyInfo>
foreach (var pInfo in properties)
{
if (IsList(pInfo.PropertyType))
{
var enumerable = (IEnumerable)pInfo.GetValue(currentObjectGraph.Source.Object, null);
var sourceEnumerator = enumerable.GetEnumerator();
var graph = new ObjectGraph(enumerable, pInfo.Name);
// this part is made up but essentially the code looks up a list of objects that can deal with this
// particular one and returns it. We then call the write method on that object
var something = GetInterfaceHandlerForObject(enumerable);
something.Write(graph);
}
}
You should make your method generic:
public void MyMethod<T>(List<T> objectList) where T:class, new()
{
objectList.Add(new T());
...
}
Casting is rarely ever necessary when you use generics. Also, your ToList() is causing a new copy of the list to be created.
One drawback to this approach is that T needs to have an empty constructor. If you need to construct an object with parameters you could instead pass in a Func<T>. You can then call it passing in a lambda expression like: (x) => new BlockMonthType(someParameter, orAnother).
I ended up resolving this by storing the underlying List T type in the ObjectGraph object and casting to that when required.
var objectList = ((IEnumerable)graphObject.Source.Object).Cast(monthAllocationRule.ListType);
Without the correct cast objectList was either null or a copy of the list. Now I can add to objectList and know it's added to the source object.
Probably not idea as Ian mentioned above but did the trick.

Remove specific entry from list (beginner in c#)

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.

C# Accessing non-interfaced methods of an object in an interface array

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()
}

ToList()-- does it create a new list?

Let's say I have a class
public class MyObject
{
public int SimpleInt{get;set;}
}
And I have a List<MyObject>, and I ToList() it and then change one of the SimpleInt, will my change be propagated back to the original list. In other words, what would be the output of the following method?
public void RunChangeList()
{
var objs = new List<MyObject>(){new MyObject(){SimpleInt=0}};
var whatInt = ChangeToList(objs );
}
public int ChangeToList(List<MyObject> objects)
{
var objectList = objects.ToList();
objectList[0].SimpleInt=5;
return objects[0].SimpleInt;
}
Why?
P/S: I'm sorry if it seems obvious to find out. But I don't have compiler with me now...
Yes, ToList will create a new list, but because in this case MyObject is a reference type then the new list will contain references to the same objects as the original list.
Updating the SimpleInt property of an object referenced in the new list will also affect the equivalent object in the original list.
(If MyObject was declared as a struct rather than a class then the new list would contain copies of the elements in the original list, and updating a property of an element in the new list would not affect the equivalent element in the original list.)
From the Reflector'd source:
public static List<TSource> ToList<TSource>(this IEnumerable<TSource> source)
{
if (source == null)
{
throw Error.ArgumentNull("source");
}
return new List<TSource>(source);
}
So yes, your original list won't be updated (i.e. additions or removals) however the referenced objects will.
ToList will always create a new list, which will not reflect any subsequent changes to the collection.
However, it will reflect changes to the objects themselves (Unless they're mutable structs).
In other words, if you replace an object in the original list with a different object, the ToList will still contain the first object.
However, if you modify one of the objects in the original list, the ToList will still contain the same (modified) object.
Yes, it creates a new list. This is by design.
The list will contain the same results as the original enumerable sequence, but materialized into a persistent (in-memory) collection. This allows you to consume the results multiple times without incurring the cost of recomputing the sequence.
The beauty of LINQ sequences is that they are composable. Often, the IEnumerable<T> you get is the result of combining multiple filtering, ordering, and/or projection operations. Extension methods like ToList() and ToArray() allow you to convert the computed sequence into a standard collection.
The accepted answer correctly addresses the OP's question based on his example. However, it only applies when ToList is applied to a concrete collection; it does not hold when the elements of the source sequence have yet to be instantiated (due to deferred execution). In case of the latter, you might get a new set of items each time you call ToList (or enumerate the sequence).
Here is an adaptation of the OP's code to demonstrate this behaviour:
public static void RunChangeList()
{
var objs = Enumerable.Range(0, 10).Select(_ => new MyObject() { SimpleInt = 0 });
var whatInt = ChangeToList(objs); // whatInt gets 0
}
public static int ChangeToList(IEnumerable<MyObject> objects)
{
var objectList = objects.ToList();
objectList.First().SimpleInt = 5;
return objects.First().SimpleInt;
}
Whilst the above code may appear contrived, this behaviour can appear as a subtle bug in other scenarios. See my other example for a situation where it causes tasks to get spawned repeatedly.
A new list is created but the items in it are references to the orginal items (just like in the original list). Changes to the list itself are independent, but to the items will find the change in both lists.
Just stumble upon this old post and thought of adding my two cents. Generally, if I am in doubt, I quickly use the GetHashCode() method on any object to check the identities. So for above -
public class MyObject
{
public int SimpleInt { get; set; }
}
class Program
{
public static void RunChangeList()
{
var objs = new List<MyObject>() { new MyObject() { SimpleInt = 0 } };
Console.WriteLine("objs: {0}", objs.GetHashCode());
Console.WriteLine("objs[0]: {0}", objs[0].GetHashCode());
var whatInt = ChangeToList(objs);
Console.WriteLine("whatInt: {0}", whatInt.GetHashCode());
}
public static int ChangeToList(List<MyObject> objects)
{
Console.WriteLine("objects: {0}", objects.GetHashCode());
Console.WriteLine("objects[0]: {0}", objects[0].GetHashCode());
var objectList = objects.ToList();
Console.WriteLine("objectList: {0}", objectList.GetHashCode());
Console.WriteLine("objectList[0]: {0}", objectList[0].GetHashCode());
objectList[0].SimpleInt = 5;
return objects[0].SimpleInt;
}
private static void Main(string[] args)
{
RunChangeList();
Console.ReadLine();
}
And answer on my machine -
objs: 45653674
objs[0]: 41149443
objects: 45653674
objects[0]: 41149443
objectList: 39785641
objectList[0]: 41149443
whatInt: 5
So essentially the object that list carries remain the same in above code. Hope the approach helps.
I think that this is equivalent to asking if ToList does a deep or shallow copy. As ToList has no way to clone MyObject, it must do a shallow copy, so the created list contains the same references as the original one, so the code returns 5.
ToList will create a brand new list.
If the items in the list are value types, they will be directly updated, if they are reference types, any changes will be reflected back in the referenced objects.
In the case where the source object is a true IEnumerable (i.e. not just a collection packaged an as enumerable), ToList() may NOT return the same object references as in the original IEnumerable. It will return a new List of objects, but those objects may not be the same or even Equal to the objects yielded by the IEnumerable when it is enumerated again
var objectList = objects.ToList();
objectList[0].SimpleInt=5;
This will update the original object as well. The new list will contain references to the objects contained within it, just like the original list. You can change the elements either and the update will be reflected in the other.
Now if you update a list (adding or deleting an item) that will not be reflected in the other list.
I don't see anywhere in the documentation that ToList() is always guaranteed to return a new list. If an IEnumerable is a List, it may be more efficient to check for this and simply return the same List.
The worry is that sometimes you may want to be absolutely sure that the returned List is != to the original List. Because Microsoft doesn't document that ToList will return a new List, we can't be sure (unless someone found that documentation). It could also change in the future, even if it works now.
new List(IEnumerable enumerablestuff) is guaranteed to return a new List. I would use this instead.

Categories