[...]
Error 2 Cannot modify the return value of
'System.Collections.Generic.List<GripperStend.JOTStatisticSaver.JOTSaverThread.TStateItem>.this[int]'
because it is not a variable C:\JOT\.NET\J501-44_gripper_stend\trunk
\GripperStend\JOTStatisticSaver.cs 1129 29 GripperStend
This is a classic "gotcha" for people new to C#, using structs (aka
"value types").
When you reference an instance of a value type, you are always operating
on a copy of that value. So the expression "aFailures
" returns a
_copy_ of the value that's in the list.
When you then access the ".value" field, you are getting accessing it on
copy of the value that was retrieved from the list. And since it's
accessed via an implicit storage location created by the compiler for
the purpose of that statement, you have no way to observe the results of
modifying that copy.
If you want to modify the members of the list itself, you need to write
something like this:
TStateItem item = aFailures;
item.value = 0;
aFailures = item;
Alternatively, don't make the type a "struct". Make it a "class". Then
you get a reference to the object within the list, and can modify it
directly.
More generally: you should try very hard to not make mutable value
types. They almost always create more headaches than they solve, in
large part because of this very issue (the compiler prevents you from
doing it wrong here, but there are plenty of other places where the
exact same issue cannot be detected by the compiler as unequivocally
wrong, and so you just get a bug in your program).
Using a "class" here, the code would work just as written. If you
really want a struct, then you can make it immutable by following the
pattern that System.String does: provide "mutating" methods that return
a new instance rather than modifying the current one:
struct TStateItem
{
public readonly byte ID;
public readonly byte failure;
public readonly double value;
public TStateItem(byte id, byte failure, double value)
{
this.ID = id;
this.failure = failure;
this.value = value;
}
public TStateItem ResetValue()
{
return new TStateItem(ID, failure, 0);
}
public TStateItem SetValue(double value)
{
return new TStateItem(ID, failure, value);
}
}
Then the line of code in question becomes:
aFailures = aFailures.ResetValue();
By the way, you have a number of non-standard/deficient things in the
code you posted, which you should at least review:
• Naming conventions. "aFailures" doesn't follow any standardnaming
convention.
• Type names should not start with a single letter "T"; rather, that
should be reserved for generic type parameters
• variable/field names should never be capitalized
• Fields should never be public. Public fields should always be
readonly. (This last one is not a naming convention, but rather a code
correctness/maintenance issue…it is less ignorable than the others).
You can find more details on Microsoft's recommendations here:http://msdn..microsoft.com/en-us/library/ms229002.aspx
At a minimum, you should at least be proficient and aware of those
recommendations, _then_ make informed decisions as to whether you're
going to follow those recommendations or not. If you do choose to
ignore those recommendations, you should at least try to follow
_something_ that the rest of the world uses.
Pete