14

操作からのデータで埋められるリストがあり、それをメモリキャッシュに保存しています。ここで、条件に基づいたリストのサブデータを含む別のリストが必要です。

以下のコードに見られるように、私はターゲットリストに対していくつかの操作を行っています。問題は、ターゲットリストに対して行っている変更がmainListに対しても行われていることです。参照のせいで同じか何かだと思います。

必要なのは、ターゲットリストでの操作がメインリスト内のデータに影響を与えないことだけです。

List<Item> target = mainList;
SomeOperationFunction(target);

 void List<Item> SomeOperationFunction(List<Item> target)
{
  target.removeat(3);
  return target;
}
4

11 に答える 11

24

はクラスであるため、メソッドにリストのクローンを作成する必要があります。これList<T>は参照型であり、参照によって渡されます。

例えば:

List<Item> SomeOperationFunction(List<Item> target)
{
  List<Item> tmp = target.ToList();
  tmp.RemoveAt(3);
  return tmp;
}

または

List<Item> SomeOperationFunction(List<Item> target)
{
  List<Item> tmp = new List<Item>(target);
  tmp.RemoveAt(3);
  return tmp;
}

また

List<Item> SomeOperationFunction(List<Item> target)
{
  List<Item> tmp = new List<Item>();
  tmp.AddRange(target);
  tmp.RemoveAt(3);
  return tmp;
}
于 2012-12-20T18:02:14.537 に答える
7

コピーへの変更が元のリストに影響を与えないように、リストのコピーを作成する必要があります。これを行う最も簡単な方法は、のToList拡張メソッドを使用することSystem.Linqです。

var newList = SomeOperationFunction(target.ToList());
于 2012-12-20T18:02:36.150 に答える
5

Listは参照型であるため、最初に新しいリストを作成して操作します。つまり、関数でリストを渡すときは、値だけでなく実際のオブジェクト自体も渡します。

targetに割り当てるだけの場合mainList、両方の変数が同じオブジェクトを指しているため、新しいリストを作成する必要があります。

List<Item> target = new List<Item>(mainList);

void List<Item> SomeOperationFunction()何も返さない(void)か、を返すため、意味がありませんList<T>。したがって、メソッドからreturnステートメントを削除するか、新しいを返しますList<Item>。後者の場合、私はこれを次のように書き直します。

List<Item> target = SomeOperationFunction(mainList);

List<Item> SomeOperationFunction(List<Item> target)
{
    var newList = new List<Item>(target);
    newList.RemoveAt(3);
    return newList;
}
于 2012-12-20T18:02:18.980 に答える
3

私は上記の答えの多くを試しました。私がテストしたすべてのもので、新しいリストを更新すると元のリストが変更されます。これは私のために働くものです。

var newList = JsonConvert.DeserializeObject<List<object>>(JsonConvert.SerializeObject(originalList));
return newlist.RemoveAt(3);
于 2019-10-29T02:44:54.837 に答える
2

新しいリストを作成しても、新しいリストのアイテムへの参照は古いリストのアイテムを指しているので、新しい参照を持つ新しいリストが必要な場合は、この拡張メソッドを使用します...

public static IEnumerable<T> Clone<T>(this IEnumerable<T> target) where T : ICloneable
{
    If (target.IsNull())
        throw new ArgumentException();

    List<T> retVal = new List<T>();

    foreach (T currentItem in target)
        retVal.Add((T)(currentItem.Clone()));

    return retVal.AsEnumerable();
}
于 2012-12-20T18:55:37.043 に答える
1

ターゲット変数は参照型です。これは、あなたがそれに行うことはすべて、あなたがそれに渡すリストに反映されることを意味します。

これを行わない場合は、メソッドに新しいリストを作成し、そのリストにtargetコンテンツをコピーしてから、新しいリストに対してremoveat操作を実行する必要があります。

参照型と値型について

于 2012-12-20T18:01:14.230 に答える
1

aListは参照型であるため、関数に渡されるのは元のリストへの参照です。

C#でパラメーターを渡す方法の詳細については、このMSDNの記事を参照してください。

目的を達成するには、リストのコピーを作成して、SomeOperationFunction代わりにこれを返す必要があります。簡単な例:

void List<Item> SomeOperationFunction(List<Item> target)
{
  var newList = new List<Item>(target);
  newList.RemoveAt(3);
  return newList; // return copy of list
}

別の回答へのコメントでOlivierJacot-Descombesが指摘しているように、次のことを覚えておくことが重要です。

[...]アイテムが参照型の場合、リストには同じアイテムへの参照が引き続き保持されます。したがって、アイテム自体を変更しても、両方のリストのアイテムに影響します。

于 2012-12-20T18:03:35.610 に答える
0

mainListをtargetに割り当てる代わりに、次のようにします。 target.AddRange(mainList);

次に、リストへの参照の代わりにアイテムのコピーがあります。

于 2012-12-20T18:04:13.377 に答える
0

デフォルトでは、非プリミティブオブジェクトは参照によって渡されるため、元のリストが変更されていることがわかります(実際には値によって渡され、値は参照ですが、それは別の問題です)。

あなたがする必要があるのは、オブジェクトのクローンを作成することです。この質問は、C#でリストを複製するためのコードを作成するのに役立ちます。C#でジェネリックリストを複製するにはどうすればよいですか?

于 2012-12-20T18:03:31.857 に答える
0

ソースリストの要素をコピーして作成したリストで新しいリストを初期化するようにしてください。

List<Item> target = mainList;する必要がありますList<item> target = new List<Item>(mainList);

于 2012-12-20T18:10:00.190 に答える
0

元のコードでは、正しく疑われているように、参照(誰かがそれをポインターと呼ぶ)を渡すだけなので、リストのコピーを作成する必要があります。

新しいリストでコンストラクターを呼び出し、元のリストをパラメーターとして渡すことができます。

List<Item> SomeOperationFunction(List<Item> target)
{
    List<Item> result = new List<Item>(target);
    result.removeat(3);
    return result;
}

または、 MemberWiseCloneを作成します。

List<Item> SomeOperationFunction(List<Item> target)
{
    List<Item> result = target.MemberWiseClone();
    result.removeat(3);
    return result;
}

また、どこにも戻り値を格納していないSomeOperationFunctionので、その部分も修正することをお勧めします(メソッドをとして宣言しましたvoid。これは何も返さないはずですが、その中にオブジェクトを返します)。この方法でメソッドを呼び出す必要があります。

List<Item> target = SomeOperationFunction(mainList);

注:リストの要素はコピーされないため(参照のみがコピーされます)、要素の内部状態を変更すると、両方のリストに影響します。

于 2012-12-20T18:13:22.767 に答える