I have a list of entries which is saved into database by following - shortened - code:
List<MyStruct> myStructList = new JavaScriptSerializer().Deserialize<List<MyStruct>>(postdata);
foreach (MyStruct myStruct in myStructList) {
if(myStruct.id==0) {
// Not in DB -> insert.
myStruct.id = (int)db.ExecuteScalar("INSERT INTO table ...");
} else {
...
}
}
// return all records with id set to auto-increment value.
return myStructList;
I want to return all records with updated id - but myStruct.id
is not writeable, because of the foreach. So I replaced the foreach by a for loop:
for(int i=0;i<myStructList.Count;i++) //foreach (MyStruct myStruct in myStructList), but writeable
{
MyStruct myStruct = myStructList[i]
if(myStruct.id==0) {
// Not in DB -> insert.
myStruct.id = (int)db.ExecuteScalar("INSERT INTO table ...");
}
}
return myStructList;
but changing myStruct does not change myStructList.
Third try: Write back into the List.
for(int i=0;i<myStructList.Count;i++) //foreach (MyStruct myStruct in myStructList), but writeable
{
MyStruct myStruct = myStructList[i]
if(myStruct.id==0) {
// Not in DB -> insert.
myStructList[i].id = (int)db.ExecuteScalar("INSERT INTO table ...");
}
}
return myStructList;
which returns the error:
Cannot modify the return value of 'System.Collections.Generic.List<MyApp.MyStruct>.this[int]' because it is not a variable.
So how on earth can I get this done?
The problem is precisely because you've got a struct - and a mutable struct at that.
The indexer will return a value - if the compiler actually did let you change that value, it wouldn't modify the value that's already in the list.
Options:
Fetch the value, modify it, then put it back in the list:
MyStruct myStruct = myStructList[i]
if (myStruct.id==0)
{
myStruct.id = (int)db.ExecuteScalar("INSERT INTO table ...");
// Copy the modified value back into the list
myStructList[i] = myStruct;
}
Change it to be a class instead of a struct, in which case your first approach will be fine.
Make the struct immutable, but create a method that returns a new value which is the same as the old one, but with a new ID. Then you'd use:
MyStruct myStruct = myStructList[i]
if (myStruct.id==0)
{
myStructList[i] = myStruct.WithId((int)db.ExecuteScalar(...));
}
(You could also create a new list of values instead of modifying the existing list, if you wanted.)
In general, mutable structs are a bad idea.
See more on this question at Stackoverflow