KeyNotFound Exception in Dictionary(of T) - c#

I'm about ready to bang my head against the wall
I have a class called Map which has a dictionary called tiles.
class Map
{
public Dictionary<Location, Tile> tiles = new Dictionary<Location, Tile>();
public Size mapSize;
public Map(Size size)
{
this.mapSize = size;
}
//etc...
I fill this dictionary temporarily to test some things..
public void FillTemp(Dictionary<int, Item> itemInfo)
{
Random r = new Random();
for(int i =0; i < mapSize.Width; i++)
{
for(int j=0; j<mapSize.Height; j++)
{
Location temp = new Location(i, j, 0);
int rint = r.Next(0, (itemInfo.Count - 1));
Tile t = new Tile(new Item(rint, rint));
tiles[temp] = t;
}
}
}
and in my main program code
Map m = new Map(10, 10);
m.FillTemp(iInfo);
Tile t = m.GetTile(new Location(2, 2, 0)); //The problem line
now, if I add a breakpoint in my code, I can clearly see that my instance (m) of the map class is filled with pairs via the function above, but when I try to access a value with the GetTile function:
public Tile GetTile(Location location)
{
if(this.tiles.ContainsKey(location))
{
return this.tiles[location];
}
else
{
return null;
}
}
it ALWAYS returns null. Again, if I view inside the Map object and find the Location key where x=2,y=2,z=0 , I clearly see the value being a Tile that FillTemp generated..
Why is it doing this? I've had no problems with a Dictionary such as this so far. I have no idea why it's returning null. and again, when debugging, I can CLEARLY see that the Map instance contains the Location key it says it does not...
very frustrating.
Any clues? Need any more info?
Help would be greatly appreciated :)

You don't show what 'Location' is but this is normal behavior if it is a class: objects are tested for Equality by comparing the references. So different instances of Location will always be unequal, even if their content is the same.
The quickest fix is to override Equals() and GetHashCode() for the Location class. And then it is a good idea to (re)design it as an immutable class (or maybe immutable struct).

Henk is correct; when you test to see if two objects are equal in .Net, you're actually asking if "reference x is pointing to the same object as reference y".
So, by default:
Location a = new Location(2, 2, 0);
Location b = new Location(2, 2, 0);
Location c = a;
bool notEqual = ( a == b ); // false
bool equal = ( a == c ); // true
To get around this, you need to override the equality methods for your Location object to compare the values for equality - the body of your Equals method, for example, might end us as something like:
return (this.x == that.x && this.y == that.y && this.z == that.z);

Thank you everyone! I really appreciate it!
I made Location into a value type and now it's working just fine.
I'm sorry for not posting the whole code, but I didn't feel it was necessary and assumed that the reader could assume that location was a simple class with x,y,z int values.
I learned many new things because of all of you and my understanding of this (generally) wonderful language is greater because of it :o)
Take care,

Related

How to deal with arrays inside a struct?

I'm looking for a way to replace some of my List objects with arrays in my project to boost performance. The reasoning is that the List I would replace do not change size often (sometimes only once), so it would make sense to swap them out with arrays. Also, I would like to prevent allocations on the heap as much as possible.
So my idea is to create a struct (ArrayStruct) with two members "Count" and "Array". The struct would have some functions to add/remove/get/set/ect... elements in the array. The count would keep count of the elements that are usable in the array, and the array would only increase in size, never decrease.
Note that this is for a very particular case because I know the array size won't be very big.
The main problem I have is when I pass the reference to an already existing ArrayStruct object (named a in the example) to another (named b in the example) - I can edit the array in it, but once I resize it in a, I get an out of range exception in b. Is this because of the way I'm updating the reference via System.Array.Resize, so that the object b somehow does not attribute this change?
The only thing I could come up with as an idea was trying to override the assignment operator so that it would create a new array on assignment... but obviously that does not work.
My ArrayStruct
public struct ArrayStruct<T>
{
[SerializeField] private int m_Count;
[SerializeField] private T[] m_Array;
public int Count => m_Count;
public void Initialize(int startSize)
{
m_Count = 0;
m_Array = new T[startSize];
}
public T GetAt(int index)
{
return m_Array[index];
}
public void SetAt(int index, T newValue)
{
m_Array[index] = newValue;
}
public void Add(T newElement)
{
if (m_Array == null) {
m_Array = new T[1];
} else if (m_Array.Length == m_Count) {
System.Array.Resize(ref m_Array, m_Count + 1);
}
m_Array[m_Count] = newElement;
m_Count++;
}
public void Remove(T element)
{
for (int i = 0; i < m_Count; ++i) {
if (!element.Equals(m_Array[i])) {
continue;
}
for (int j = index; j < m_Count - 1; ++j) {
m_Array[j] = m_Array[j + 1];
}
m_Count--;
m_Array[m_Count] = default(T);
break;
}
}
//Trying to overload the = operating by creating a auto cast, this gives a compile error
/*public static implicit operator ArrayStruct<T>(ArrayStruct<T> otherArray)
{
var newArray = new ArrayStruct<T>();
newArray.m_Count = otherArray.Count;
newArray.m_Array = new T[otherArray.Length];
otherArray.m_Array.CopyTo(newArray.m_Array);
return newArray;
}*/
An example showcasing the problem
var a = new ArrayStruct<string>()
a.Add("hello");
var b = a;
print (b.GetAt(0)); //"hello"
a.SetAt(0, "new value for a");
print(b.GetAt(0));//"new value for a" , changing a changed b because the array is the same in both, this is bad
a.Add("resizing array");
print (b.GetAt(1)); //"Out of range exception" , because the array was resized for a but not for b therefore the connection broke
So do any of you have an idea of how I could make a new copy the array when I assign the struct to another variable?
Of course, I know I could use a function to do something like so
b = new ArrayStruct(a);
But I want it to be implicit. Or if there was a way to prevent assignments that would also work for me.
var a = new ArrayStruct();//let this work
var b = a; //Prevent this from happening
If you have any other solutions for replacing Lists with arrays conveniently please let me know
So do any of you have an idea of how I could make a new copy the array when I assign the struct to another variable? Of course, I know I could use a function to do something like so b = new ArrayStruct(a); But I want it to be implicit.
You can't do that. If a is a struct and you execute var b = a, then it will always just set b to a shallow copy of a; there's no way to change that behavior.
Doing something like b = new ArrayStruct(a) is the best you can do.
You're not understanding what the "=" operator is doing there. Objects are defined by reference, meaning when you write var b = a; you are actually asking for what you wish to avoid to happen, that is - object "b", pointing to the same object, which is "a".
You're passing the object "b" to point to the reference of object "a", which object holds the address to the object in question you defined, using the new keyword var a = new ArrayStruct<string>()
Your operator overloading does not work because you can't use it for conversions of the same type as the class you're writing the operator in. You'd either have to make a separate object (class), which would defeat the point you're trying to fix, or pass the m_array instead: public static implicit operator ArrayStruct<T>(T[] array)
You can also do something like this:
public static ArrayStruct<T> CopyFrom (ArrayStruct<T> array)
{
var newArray = new ArrayStruct<T>();
newArray.m_Array = new T[array.Count + 1];
newArray.Count = array.Count;
Array.Copy(array.m_Array, 0, newArray.m_Array, 0, array.m_Array.Length);
return newArray;
}
Now it should work exactly as you wanted.
var a = new ArrayStruct<string>();
a.Add("hello");
var b = ArrayStruct<string>.CopyFrom(a);
a.SetAt(0, "new value for a");
a.Add("resizing array");
Console.WriteLine(b.Count); // b returns 1
Console.WriteLine(a.Count); // a returns 2
As to why your index was going out of bounds, i.e it did not preserve the reference found in "a", this is all in correlation with references, yet again.
In the following code System.Array.Resize(ref m_Array, Count + 1); you're changing the reference found for object m_array in "a", when you're adding the new element with the line a.Add("resizing array");. That essentially means that your "a" object's m_array (which is another object of type array[]) is now pointing to a new object (of type array[]), which is of a new size.
Okay, but object "a" is now using the new reference, whilst object "b" is still using the old one. m_array in object "b" only has a single element, while the new m_array object in "a" has the newly added element "resizing array", along with any previously added ones.
I believe that's how System.Array.Resize works? Edit me if I'm wrong.
Below is a resource explaining how to do a deep cloning of an object, if that's what you truly wish to do (i.e create a completely new copy of an object, as well as any other objects inside)
Deep cloning of objects

Please explain me behaviour of C#. Object from reference

I have method with one argument which is instance of my created class - Chessfield which contain three tables - one of integers and two of bools.
In the method I have also List of Chessfield which is the return object of my method.
I am modifying chessfield (so the object from reference) and add it on list List.Add(Chessfield) several times (one time after each change).
In the end return object (so list contain several object of Chessfield) all instances are the same unrespecting my changes !
I have read similar topic and try to put 'ref' before argument and the place where I proceed this method.
Without success also I tried to create instance of Chessfield inside the method and assign to it Chessfield object from reference, then making changes on internal created object.
How I can solve it ? In the end I need to receive list of objects which each is a little bit modified from original one (from reference).
Have a nice day !!
p.s. If the code will be helpful then I cut and paste general idea code.
EDIT:
Joel undrestand me Good ! The difference is that inside object are tables and it makes the problem more complex, because I do few changes in these tables in compare to this original object. To be more clear I paste my code:
public class Chessfield
{
public int[] pieces = new int[64];
public bool[] blacks = new bool[64];
public bool[] whites = new bool[64];
public Chessfield(int[] pieces, bool[] blacks, bool[] whites)
{
this.pieces = pieces;
this.blacks = blacks;
this.whites = whites;
}
public Chessfield()
{
}
}
And method look like this:
static public List<Chessfield> MakeAllMovesForWhites(Chessfield chessfieldModel)
{
List<Chessfield> listOfPossibleMoves = new List<Chessfield>(); // list containing chessfields with changed position of figures
int indexOfCurrentPosition = 0; //start with field 0 (most top left)
foreach (bool singleEnemyChecker in chessfieldModel.whites) //iterate all fields, table of whites contain information if white field stand on the field (true, otherwise false),
{
if (singleEnemyChecker == true) //so algorithm will proceed only fields with white figure
{
int kindOfPiece = chessfieldModel.pieces[indexOfCurrentPosition]; // (table pieces contain information which kind of figure stand on particular field 0 -> empty, 1 -> soldier, 2-> tower, 3 -> horse etc...
switch (kindOfPiece)// (based on figure at field it is going to predict all possible moves
{
case 2: // tower case
if (indexOfCurrentPosition % 8 != 0) // check if the field is not most left, otherwise leave
{
int localIndexIterator = indexOfCurrentPosition; //localIndex iterate all possible moves in left direction
while (localIndexIterator % 8 != 0) // checking if tower is standing on the most left field
{
localIndexIterator = localIndexIterator - 1; //iterate all possible moves of tower for left direction
if (chessfieldModel.pieces[localIndexIterator] == 0) //if there are no figures on checking field proceed:
{
chessfieldModel.pieces[indexOfCurrentPosition] = 0; // erase tower from original position
chessfieldModel.whites[indexOfCurrentPosition] = false; // and mark that white tower is not standing there anymore
chessfieldModel.pieces[localIndexIterator] = 2; // put tower on new place
chessfieldModel.whites[localIndexIterator] = true; // and mark that on new place there is white figure
listOfPossibleMoves.Add(chessfieldModel); // here I add changed object of chessfield to list
chessfieldModel.pieces[indexOfCurrentPosition] = 2; // here I come back to original chessfield
chessfieldModel.whites[indexOfCurrentPosition] = true;
chessfieldModel.pieces[localIndexIterator] = 0;
chessfieldModel.whites[localIndexIterator] = false;
}
else //if there is figure at checking field
break; //leave this case
}
}
if (indexOfCurrentPosition % 8 != 7) // right direction case
{
// here is similar code to the sample above
}
if (indexOfCurrentPosition / 8 != 0) //top direction case
{
// here is similar code to the sample above
}
if (indexOfCurrentPosition / 8 != 7) //bottom direction case
{
// here is similar code to the sample above
}
break;
// here are another figures horse and so on...
}
}
indexOfCurrentPosition++; // go to next field...
}
return listOfPossibleMoves; //return list of changed chessfields
}
and here I call method
Logic.MakeAllMovesForWhites(currentChessfield);
I understand what is the problem. And Joel - you are explaining very good ! (y) Thank you.
My first attemp to solve it was (before I ask here):
Chessfield abc = new Chessfield();
abc = chessfieldModel;
abc.pieces[indexOfCurrentPosition] = 0;
abc.whites[indexOfCurrentPosition] = true;
abc.pieces[localIndexIterator] = 2;
abc.whites[localIndexIterator] = false;
listOfPossibleMoves.Add(abc);
Fail. I tried this in every case (create for every figure and every direction). By the way there are 33 different cases how figure can move in chess, so I had this piece of code above in this 33 places (but sometimes I put different things to tables..). But figure like tower can move left for 1,2,3,4,5,6,7 fields if there are not pieces on the left.. and this is problem that I must to create always new instance and I do not know how, because I must to create unique instance, change it a bit, and add to list.. always unique, but in different cases.
Also I have tried your solution Joel, but the problem is that I need to do some changes to original chessfield (4 rows always, but different changes for different figures).
But I tried to create a new instance, add it to list, and then change it while is already on list. Doesn't work and logic is not proper even then.
listOfPossibleMoves.Add(new Chessfield() { pieces = chessfieldModel.pieces, blacks = chessfieldModel.blacks, whites = chessfieldModel.whites });
listOfPossibleMoves[listOfPossibleMoves.Count - 1].pieces[indexOfCurrentPosition] = 0;
listOfPossibleMoves[listOfPossibleMoves.Count - 1].whites[indexOfCurrentPosition] = false;
listOfPossibleMoves[listOfPossibleMoves.Count - 1].pieces[localIndexIterator] = 2;
listOfPossibleMoves[listOfPossibleMoves.Count - 1].whites[localIndexIterator] = true;
EDIT: So maybe coming back to my first method, but how I can create unique name for objects creating in the same place ? May you recommend some technique or what I can do in this situation ?
Thanks Joel and all :)
Have a nice day (or night) everybody !
It would really help to see code in the question, but it sounds like you're doing something like this:
public class ChessField
{
public bool b1;
public bool b2;
public int i1;
}
public List<ChessField> Method(ChessField c)
{
var result = new List<ChessField>();
for (int i = 0;i<3;i++)
{
c.i1 = i;
result.Add(c);
}
return result;
}
Here's the problem: you are adding the same object to the list. result[0] refers to the same object instance as result[1] refers to the same object instance as result[2] refers to the same object instance as c. Changing a property in c changes it everywhere else in this code, because they all are variables for the same object in memory. If you need the objects to be different, you must do something to create new object instances, like this:
public List<ChessField> Method(ChessField c)
{
var result = new List<ChessField>();
for (int i = 0;i<3;i++)
{
result.Add(new ChessField() {b1 = c.b1, b2 = c.b2, i1 = i});
}
return result;
}
or my preferred style would do this:
public IEnumerable<ChessField> Method(ChessField c)
{
return Enumerable.Range(0, 3)
.Select(i => new ChessField() {b1 = c.b1, b2 = c.b2, i1 = i});
}

C# - Object variable assignment failing

I'm having some trouble understanding why my variable has a null value.
Here's my class constructor:
private GraphNode current;
private GraphNode goal;
private GraphNode start;
private List<GraphNode> path;
private List<GraphNode> origin;
public Graph()
{
current = new GraphNode(0, 0);
goal = new GraphNode(0, 0);
start = new GraphNode(0, 0);
path = new List<GraphNode>();
origin = new List<GraphNode>();
}
Defenition of method SetPathing:
public void SetPathing(int mouseX, int mouseY)
{
if (Contains((int)mouseX / 32, (int)mouseY / 32))
{
goal = GetNode((int)mouseX / 32, (int)mouseY / 32);
current = goal;
path.Add(current);
while ((current.X != start.X) && (current.X != start.X))
{
current = origin.Where(keyValuePair => (keyValuePair.Key.X == current.X) && (keyValuePair.Key.X == current.Y)).Select(keyValuePair => keyValuePair.Value).LastOrDefault();
path.Add(current);
}
}
}
When I break on the start of the while-loop in SetPathing I see the following info in the locals screen:
current null PathFinding.GraphNode
goal {PathFinding.GraphNode} PathFinding.GraphNode
X 0 int
x 0 int
Y 5 int
y 5 int
How is that possible after having clearly assigned the reference value of goal to current?
I'm probably missing something stupid here, but I haven't found it after looking for two hours. No asynchronous going on here.
EDIT: Didn't want to be overtly verbose with my initial question, here's some extra details, my apologies. Here are the details of Contains, GetNode and GetNodeIndex. Nothing fancy, I'm an amateur.
public int GetNodeIndex(int x, int y)
{
// Find the node index in the list based on x and y
// Return -1 if not found
return nodes.FindIndex(n => (n.X == x) && (n.Y == y));
}
public GraphNode GetNode(int x, int y)
{
// Find the node in the list based on x and y
// Return null if not in list
int nodeIndex = GetNodeIndex(x, y);
if (nodeIndex != -1)
{
return nodes[nodeIndex];
}
return null;
}
public bool Contains(int x, int y)
{
// Check if the returned value is not -1
if (GetNodeIndex(x, y) != -1)
{
return true;
}
}
The usecase is litterally just along the lines of the following:
using System;
namespace Graphs
{
class Program
{
static void Main()
{
Graph graph = new Graph(20, 20);
graph.SetPathing(Mouse.GetState().X, Mouse.GetState().Y);
}
}
}
Let's dissect your code here.
goal = GetNode((int)mouseX / 32, (int)mouseY / 32);
Here, you've set the variable goal to point to a GraphNode object. So, for the sake of simplicity, we'll call it A. At this point your values look like this:
goal -> A
current -> null
Next, you do this:
current = goal;
And now, your values look like this:
goal -> A
current -> A
Later during your while loop, you call this:
current = origin.Where(keyValuePair => (keyValuePair.Key.X == current.X) && (keyValuePair.Key.X == current.Y)).Select(keyValuePair => keyValuePair.Value).LastOrDefault();
For the sake of simplicity, we'll call the result of this where clause B. So, now your values look like this:
goal -> A
current -> B
All that you have done here is change current to point to a new value.
You showed the code for the default Graph constructor,
public Graph()
not the one being used.
Graph graph = new Graph(20, 20);
Is there any difference between them?
Also, are you sure your code is in sync with the assembly? i.e. from your description it seems your break point is on this line
while ((current.X != start.X) && (current.X != start.X))
Are you sure when you were debugging, it was indeed executing only upto here when the debugger stopped, or it could have already executed the filtering code two lines down?
I'm not sure how this is possible, but the answer appears to be that this is in fact not the first iteration of the While-loop.
I had my break point set to the loop, and the results I posted above were from the first hit of that break point. However, after adding a variable that acted as an iteration counter it turned out this was in fact NOT the first iteration, but the third one. Following this discovery I went on to improve the code in the while loop to prevent current being set to null.
I'm not sure how this could happen. I'm using Visual Studio 2013 Express for Desktop. Never encountered anything like this before.

Why is my variable of type List<Point> being changed even though I'm not using references?

I have a variable called temp which is of type List<Point>. For some reason, when I call sanitize(temp), the variable temp seems to change. I know that the variable temp changes, because the output I get on C:\out.bmp is different if I include the sanitize(temp) line or not. The output I am getting from the messagebox is "temp was not changed."
List<Point> original = temp;
sanitize(temp);
if (temp.Equals(original)) {
MessageBox.Show(#"temp was not changed.");
} else {
MessageBox.Show(#"temp was changed.");
}
outputPointsOnBitmap(temp.ToArray(), ref windowBitmap, Color.Yellow);
windowBitmap.Save("C:\\out.bmp");
For the curious, here is more source code:
private void outputPointsOnBitmap(Point[] points, ref Bitmap bitmap, Color markerColor) {
foreach (Point point in points) {
bitmap.SetPixel(point.X, point.Y, markerColor);
}
}
private List<Point> sanitize(List<Point> crossPoints) {
SortedSet<int> indexesToDelete = new SortedSet<int>();
for (int i = 0; i < crossPoints.Count() - 1; i++) {
if (Math.Abs(crossPoints[i + 1].X - crossPoints[i].X) <= 5 &&
Math.Abs(crossPoints[i + 1].Y - crossPoints[i].Y) <= 5) {
indexesToDelete.Add(i);
indexesToDelete.Add(i + 1);
}
}
foreach (int i in indexesToDelete.Reverse()) {
crossPoints.RemoveAt(i);
}
return crossPoints;
}
This is driving me nuts.
When you do:
List<Point> original = temp;
You make the variable original refer to the list that temp refers to.
So any changes that sanitize makes to temp are also visible in original. temp.Equals(original) returns true because they are the same object. If you want original to be a new list with the same items as temp, construct a new List object:
List<Point> original = new List<Point>(temp);
You say you're not using references, but List<T> is a reference type because it doesn't inherit from ValueType - when you assign or pass it you're always using references.
Here's a good breakdown of the difference between value and reference types in .Net:
http://www.albahari.com/valuevsreftypes.aspx
As Jordy Langen points out, temp.Equals(original) will always return false now, because the the two lists are different objects (and that's what Object.Equals looks at for reference types). If you want to see whether the sanitize function changed the list at all, you can use Enumerable.SequenceEqual:
if (temp.SequenceEqual(original)) {
MessageBox.Show(#"temp was not changed.");
} else {
MessageBox.Show(#"temp was changed.");
}
If you want original to not change, do this:
List<Point> original = new List<Point>(temp);
sanitize(temp);
That will create a new List<Point> with the contents of temp. Otherwise, List<Point> original = temp just creates a new reference (original) to the same memory location which contains your list (temp).
In order to check if your 2 lists are different in your case, check their Count (since Equals will always return false).
if( temp.Count != original.Count )
{
// now you know that some items were removed in your sanitize method
}
temp changes because you're passing a reference to it into sanitize which is assigned to the crossPoints variable. Because it's passed by reference any changes to crossPoints (via the call to RemoveAt) also affect temp since they point to the same list.
When you say:
List<Point> original = temp;
You're making temp and original refence the same list. It does not create a copy of the list.
Temp and original are not objects, they are references to objects, in your case, they both reference the same list object. Normally, equals does reference comparison on objects, so it will say they are equal. Either way you are comparing a list object to itself. In your sanitize method, you change the same list.
It is being modified because it is being passed as a reference, so the delete operation is actually being performed on the same reference the temp variable holds. you may be the desired result if you do the following:
private List<Point> sanitize(List<Point> crossPoints) {
var workset = new List<Point>(crosspoints);
SortedSet<int> indexesToDelete = new SortedSet<int>();
for (int i = 0; i < workset.Count() - 1; i++) {
if (Math.Abs(workset[i + 1].X - workset[i].X) <= 5 &&
Math.Abs(workset[i + 1].Y - workset[i].Y) <= 5) {
indexesToDelete.Add(i);
indexesToDelete.Add(i + 1);
}
}
foreach (int i in indexesToDelete.Reverse()) {
workset.RemoveAt(i);
}
return workset;
}
of course keep in mind this is an O(n) operation since you are making a copy of the references in the list
This statement:
List<Point> original = temp;
original does now have the same reference as temp. Meaning: All changes you apply to the temp variable are also applied to the original variable because they share the same reference.
You should create a deep copy of the list to make this work. One more thing:
The Equals will always return false if you use a deep copy. Equals check if the references are equal. You most probable need to do check based on the items in the list.
Your list temp is an object, and objects are passed by reference, so your sanitize method is changing the underlying object.
However, your output says it's not changed because you assign original = temp, meaning that your variable original is a pointer to the same object as your variable temp, so when you compare the two they are equal, even though the object has actually changed since before it was passed to sanitize.

why when change array in structure all references change?

I am working on C# project and my code is somthing like this:
public struct Point
{
public int X;
public int[,] arr;
}
List<Point> po=new List<Point>();
void func()
{
Point p1;
p1.arr = new int[1, 1];
p1.X = 10;
p1.arr[0, 0] = 1;
func2(p2);
p1.X=20;
p1.arr[0,0]=10;
}
void func2(Point h)
{
po.Add(h);
}
when I track this code and return from func2 , when change p1.x , my point in list (x parameter) not changed but when change p1.arr to 10,my point (arr parametr) in list also change from 1 to 10.why this happened an how can fix this problem?
Structs have value semantics. This means that changing p1.x is changing a value, not a reference. You have a local value p1 that you are changing. When you change a value in the array, you're changing that copy of the value.
Structs are value types in C#, while classes are references. Try passing the point to func2 with the ref modifier.
void func2(ref Point h){
....
}
Actually, thanks to JG in SD's comment, it should be more like this:
void func2(ref Point po, Point h){
po.Add(h);
}
And on further review, that's still wrong. Basically, when you're adding the Point to the List, it's copying the Point by value to the list.
p1 and po.Last() have the same values, but refer to different objects. If Point were a class, you wouldn't have this problem.
You could do this right after adding p1 to po, but it's dumb and unwieldy:
po.Add(p1);
var len = po.Count;
po[len-1].X = 20;
po[len-1].arr[0,0]=10;
You can't do:
po.Add(p1);
var len = po.Count;
var pNew = po[len-1];
// p1 and pNew are different objects in memory, but with the same values
pNew.X = 20;
pNew.arr[0,0]=10;
Well, technically, you can do exactly that, but since they're different objects in memory, it won't do what you're hoping.
Just switch Point to a class unless you have a serious need not to do so.

Categories

Resources