Modify Struct Variable in a Dictionary

Modify Struct variable in a Dictionary

The indexer will return a copy of the value. Making a change to that copy won't do anything to the value within the dictionary... the compiler is stopping you from writing buggy code. If you want to do modify the value in the dictionary, you'll need to use something like:

// Note: copying the contents to start with as you can't modify a collection
// while iterating over it
foreach (KeyValuePair<string, MapTile> pair in tilesData.ToList())
{
MapTile tile = pair.Value;
tile.bgFrame = tile.bgFrame >= tile.bgAnimation ? 0 : tile.bgFrame + 1;
tilesData[pair.Key] = tile;
}

Note that this is also avoiding doing multiple lookups for no good reason, which your original code was doing.

Personally I'd strongly advise against having a mutable struct to start with, mind you...

Of course, another alternative is to make it a reference type, at which point you could use:

// If MapTile is a reference type...
// No need to copy anything this time; we're not changing the value in the
// dictionary, which is just a reference. Also, we don't care about the
// key this time.
foreach (MapTile tile in tilesData.Values)
{
tile.bgFrame = tile.bgFrame >= tile.bgAnimation ? 0 : tile.bgFrame + 1;
}

Modify struct variable

There are a couple things wrong with what you're trying to do.

In 99.999999999% of cases, structs should be readonly. See Microsoft design guidelines https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/struct

X DO NOT define mutable value types.

Mutable value types have several problems. For example, when a
property getter returns a value type, the caller receives a copy.
Because the copy is created implicitly, developers might not be aware
that they are mutating the copy, and not the original value. Also,
some languages (dynamic languages, in particular) have problems using
mutable value types because even local variables, when dereferenced,
cause a copy to be made.

You should also not mutate an object that is being used as a dictionary key. Dictionaries are based on hash values, and if you change a field of the key, you will change its hash value. See: https://stackoverflow.com/a/3007334/4415493

The Dictionary type makes no attempt to protect against
the user modifying the key used. It is purely left up to the developer
to be responsible in not mutating the key.

If you think about this a bit this is really the only sane route that
Dictionary can take. Consider the implication of doing an
operation like a memberwise clone on the object. In order to be
thorough you'd need to do a deep clone because it will be possible for
an object referenced in the key to also be mutated and hence affect
the hash code. So now every key used in the table has it's full object
graph cloned in order to protect against mutation. This would be both
buggy and possibly a very expensive operation.

How to update value in dicitonary with struct member error

You are modifying a copy of the value stored in the dictionary, so it will not affect the original value. And that is why the compiler is preventing you to do that.
You need to recreate the object:

node_info[edge.node_identifier] = (node_info[edge.node_identifier].inputs, edge.node_descriptor.Count(c => c == ',') + 1);

The final code will be something like this:

public bool Validate(IEnumerable<(string node_identifier, string node_descriptor)> nodes, IEnumerable<(string node_identifier, string node_descriptor)> edges)
{
Dictionary<string, (int inputs, int outputs)> node_info = nodes.ToDictionary(node => node.node_identifier, node => (-1, -1));
foreach (var edge in edges)
{
node_info[edge.node_identifier] = (node_info[edge.node_identifier].inputs, edge.node_descriptor.Count(c => c == ',') + 1);
}
}

You can improve that code avoiding multiple lookups into the dictionary, but i will leave that to you :)

How can i access Structure property that is inside Hashtable?

Dictionary will not allow me to modify that directly

Neither will a Hashtable. This has nothing to do with Hashtable vs Dictionary. The problem is that your "value" in either case is a value type, so you can't modify it directly within the collection. If you really need a struct, then you'll have to create a new value and put it back into the hashtable:

bags.Add(1, new Bag() {apple_type="apple1",orange_type="orange1"});

//((Bag)bags[1]).apple_type="apple2";
var bag = (Bag)bags[1];
bag.apple_type = "appple2";
bags[1] = bag;

But mutable structs are generally bad, so I would either get the value of the struct right the first time (rather than modifying it ourside of the initial load loop) :

// row counter used for list view
int row_counter = 0;

while (data_Reader.Read()) { // Keep reading data from memory until there is no row
{
var appleType = data_Reader[0].ToString();
Bag tempBag = new Bag() {
apple_type = appleType,
orange_type = getOrangeType(appleType)
};
bags.Add(row_counter, tempBag);
row_counter++;
}

or use a class.

Note that the same code works exactly the same way whether you use a Hashtable or a Dictionary.

Also, since your "key" is just an incrementing number (and not tied to the value at all), you could just as well use a List<Bag> and access the items by index.

Create Dictionary of Custom Struct and Access Properties in C#

Structs are value types, when you pass a struct, it creates a copy of the struct. This is especially a problem with mutable structs since when you pass the struct to a method (or get it out of a property) the struct is copied by value and then you are modifying the copy, not the original.

The fix is to avoid mutable structs and to use a class instead. Only use structs where the value (of all its fields) is fixed during construction.

Edit

To expand on this a little bit, we can examine the line:

pieceDict[pCode].pCode = pCode;

What is happening here is that the first part, pieceDict[pCode] returns a copy of the value (in the case of a value type), which is then operated on by the .pCode part, which you assign it to pCode, but because you are working on a copy, and not what is stored in the dictionary, it will not be saved. The compiler is smart enough to notice that you are trying to assign to it and that it will be thrown away anyway, so it gives you the error.

In my opinion the error could be better worded, something like "assignment to a copy of a value type does not result in an assignment of the underlying value", because as a new-ish programmer when it says that the assignment fails because its not a variable is a little confusing. The dictionary is a variable, the item that went in is a variable, so its hard to understand why the value is not a variable.

Why is this one line of code different than the two above it?

Since Key is struct and struct is a value type, when you access it via a Method, Property or Indexer it returns a copy of the struct instance not the instance itself. Try declaring Key as class. For detailed information you can search for difrences between struct and class or value and reference types.

modifiy dictionary value as out parameter and reference

What if someone creates a new MovementspeedComponent using float
movementspeed

Types are good for keys when we have one object/collection per each type otherwise a Dictionary<Type, object> isn't a good fit, key should be unique.

When I try to modify the components they are not modified by reference

Since all of components are structs this line of code:

components.TryGetComponent(out Position fooPosition)

Gets a copy of struct that we have in the dictionary.
A quote from C# guide:

Structs are copied on assignment. When a struct is assigned to a new
variable, all the data is copied, and any modification to the new copy
does not change the data for the original copy. This is important to
remember when working with collections of value types such as
Dictionary.

What if someone creates a new MovementspeedComponent using float
movementspeed and tries to add it?

Changing the value of an element in a list of structs

MyList[1] = new MyStruct("bob");

structs in C# should almost always be designed to be immutable (that is, have no way to change their internal state once they have been created).

In your case, what you want to do is to replace the entire struct in specified array index, not to try to change just a single property or field.



Related Topics



Leave a reply



Submit