特定の位置でその構造体の値を編集しList<T>
たい。構造体のコピーを作成し、コピーを編集し、リスト内のエントリを置き換えることなく、これはまったく可能ですか?
3 に答える
List
いいえ、それを行うには、 /によって提供されない内部配列の要素への参照が必要ですIList
。
必要に応じて、安全でないコードと配列でそれを行うことができます。
おそらく最善の策は、構造体にフィールドを直接公開させてから、次のようなコードを使用することです。
var temp = myList[3]; temp.X += 4; myList[3] = 一時;
私は、.net がリスト アイテムを更新する手段を提供できないことを .net の重大な弱点と考えていますが、それでも、フィールド構造体を表現したい場合には、exposed-field struct がどの代替手段よりもはるかに優れていると考えています。他のそのようなグループ (点の座標、四角形の原点とサイズなど) に「結合」されるべきではない直交値の小さなグループ。構造体は「不変」であるべきであるという概念は、しかし、それが良いアドバイスであるとは限りません。このような概念は、主に次の 2 つのことに由来します。
- コンストラクター外のメンバーで「this」を変更する構造体は風変わりです。このような癖は、プロパティ セッターに適用されていました (現在もある程度適用されています) が、単にフィールドを直接公開する構造体には適用されません。Microsoft はすべての構造体フィールドをプロパティでラップしたため、変更可能な構造体にフィールドが公開されていれば、適切なセマンティクスを持つことができたかもしれませんが、風変わりなセマンティクスになってしまいました。次に Microsoft は、風変わりなセマンティクスを、フィールドをプロパティで不必要にラップするのではなく、構造体が可変であるという事実にあると非難しました。
- 一部の人々は、値型と参照型を別個の種類のエンティティとして持つのではなく、1 種類のオブジェクトしか持たない .net をモデル化することを好みます。いわゆる「不変」の値型の動作は参照型の動作に十分近いため、同じものであるかのように振る舞うことができますが、簡単に変更できる値型の動作は大きく異なります。実際には、いわゆる「不変」値型が参照型とは異なる動作をするすべてのコーナー ケースを理解するよりも、公開フィールド値型の動作を理解する方が簡単です。前者を理解せずに後者を理解することは不可能です。値の型は不変のふりをするかもしれませんが、実際には不変の値の型などは存在しないことに注意してください。
実際には、型が直交値の小さなグループを表すと想定されている場合、公開フィールド構造体は完全に適合します。のアイテムのフィールドを更新するために上記のような不格好なコードを使用する必要がある場合でも、List<structType>
クラス型またはいわゆる「不変」構造体を使用する代替手段よりも優れています。myList
上記のコードを完全に理解するには、それが公開されたフィールドを持つ構造体であることを知るX
だけで十分です。クラスまたは「不変」構造体を使用している場合、リモートで適切な唯一の代替手段は になりますがmyList[3] = myList[3].WithX(myList[3].X + 4);
、それには、問題の型がメソッドを提供する必要がありますWithX
(おそらくWithWhatever()
各フィールドのメソッド)。そのようなメソッドは、メソッドが実際に何をするかを確実に知るために読まなければならないコードの量を何倍にも増やします(の値を除いて古いものと同じである新しいインスタンスを返すと予想されるかもしれませんが、関連するすべてのコードを読むまではわかりませんが、対照的に、それが構造体型の公開されたフィールドであることを知っていれば、上記のコードが何を行うかを知るのに十分です。WithX
X
X
J.Richter の「C# 経由の CLR」、第 3 版から:
値型は不変である必要があります。つまり、型のインスタンス フィールドを変更するメンバーを定義してはなりません。実際、フィールドを変更しようとするメソッドを誤って記述した場合にコンパイラがエラーを発行するように、値型のフィールドを読み取り専用としてマークすることをお勧めします。
...
値型と参照型は、使用方法によって動作が大きく異なることに注意してください。
次のコードを検討してください。
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;
}
}
そしてそれは使用法です:
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();
}
出力は次のとおりです。
0 10
だから、それはあなたが必要とすることをします。
ただし、同じことは機能しませんList<T>
。アレクセイ・レベンコフが言及した理由によると思います。そのため、問題の型がインスタンスごとに不変でない場合は、に変更struct
することを強くお勧めします。class