list of stuct, changing it`?

S

Sonnich Jensen

Hi

This does not work:


struct TStateItem
{
public byte ID;
public byte failure;
public double value;
}
List<TStateItem> aFailures = new List<TStateItem>();
// clearing values
for (i = aFailures.Count - 1; i >= 0; i--)
{
aFailures.value = 0; <- fails
here...
}



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

What do I do wrong?
 
J

jodleren

[...]
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
What do I do wrong?

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


Thanks. One learns every.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top