I have a struct which I put in a List<T>
, I want to edit some value in that struct at a specific position. Is this at all possible without making a copy of the struct, editing the copy, and replacing the entry in the List?
问题:
回答1:
No, to be able to do it you need reference to element of inner array which is not provided by List
/IList
.
You can do that with unsafe code and arrays if you have to.
回答2:
From J.Richter's "CLR via C#", 3rd edition:
Value types should be immutable: that is, they should not define any members that modify any of the type’s instance fields. In fact, I recommended that value types have their fields marked as readonly so that the compiler will issue errors should you accidentally write a method that attempts to modify a field.
...
Just keep in mind that value types and reference types have very different behaviors depending on how they’re used.
Consider this code:
public interface IChangeStruct
{
int Value { get; }
void Change(int value);
}
public struct MyStruct : IChangeStruct
{
int value;
public MyStruct(int _value)
{
value = _value;
}
public int Value
{
get
{
return value;
}
}
public void Change(int value)
{
this.value = value;
}
}
and it's usage:
static void Main(string[] args)
{
MyStruct[] l = new MyStruct[]
{
new MyStruct(0)
};
Console.WriteLine(l[0].Value);
l[0].Change(10);
Console.WriteLine(l[0].Value);
Console.ReadLine();
}
The output is:
0 10
So it does what you need.
However the same won't work for List<T>
. I guess by the reason, mentioned by Alexei Levenkov. So, I would strongly recommend you to change struct
to class
if the type in question is not immutable per instance.
回答3:
Your best bet is probably to have your structures expose their fields directly, and then use code like:
var temp = myList[3]; temp.X += 4; myList[3] = temp;
I consider the failure of .net to provide any means of updating list items in place to be a significant weakness in .net, but would still consider an exposed-field struct as being far superior to any alternative in cases where one wishes to represent a small group of orthogonal values which should not be "attached" to any other such group (such as the coordinates in a point, the origin and size of a rectangle, etc.) The notion that structs should be "immutable" has been repeated as mantra for a long time, but that doesn't mean it's good advice. Such notion stems largely from two things:
- Structs which modify `this` in any members outside their constructors are quirky. Such quirks used to (and to some extent still do) apply to property setters, but not to structs which simply expose their fields directly. Because Microsoft wrapped all struct fields in properties, this meant that while mutable structures could have had sensible semantics if they'd had exposed fields, they ended up with quirky semantics; Microsoft then blamed the quirky semantics on the fact that structs were mutable, rather than on the needless wrapping of fields with properties.
- Some people like to model .net has only having one kind of object, as opposed to having value types and reference types as distinct kinds of entities. The behavior of so-called "immutable" value types is close enough to that of reference types that they can pretend they're the same thing, whereas the behavior of easily-mutable value types is vastly different. In reality, it's easier to understand the behavior of exposed-field value types than to understand all the corner cases where so-called "immutable" value types behave differently from reference types, and understanding the latter is impossible without understanding the former. Note that while value types may pretend to be immutable, there is in reality no such thing as an immutable value type. The only distinction is between those which can be mutated conveniently and those which can only be mutated awkwardly.
In reality, if a type is supposed to represent a small group of orthogonal values, an exposed-field struct is a perfect fit. Even if one has to use clunky code like that shown above to update a field of an item in a List<structType>
, it's better than any alternative using class types or so-called "immutable" structs. Knowing that myList
is a structure with an exposed field X
would be enough to completely understand the code above. The only remotely decent alternative if one were using a class or "immutable" struct would be myList[3] = myList[3].WithX(myList[3].X + 4);
, but that would require that the type in question to offer a WithX
method (and presumably a WithWhatever()
method for each field). Such methods would increase many fold the amount of code one would have to read to find out for certain what a method would actually do (one might expect that WithX
would return a new instance which was identical to the old one except for the value of X
, but one wouldn't know until one read all the code involved; by contrast, knowing that X
is an exposed field of the structure type would be sufficient to know what the above code would do.