[C#] ToList () — 새 목록을 작성합니까?

수업이 있다고 가정 해 봅시다

public class MyObject
{
   public int SimpleInt{get;set;}
}

그리고 List<MyObject>,을 가지고 있고 , ToList()중 하나를 변경 SimpleInt하면 변경 사항이 원래 목록으로 다시 전파됩니다. 즉, 다음 방법의 결과는 무엇입니까?

public void RunChangeList()
{
  var objs = new List<MyObject>(){new MyObject(){SimpleInt=0}};
  var whatInt = ChangeToList(objs );
}
public int ChangeToList(List<MyObject> objects)
{
  var objectList = objects.ToList();
  objectList[0].SimpleInt=5;
  return objects[0].SimpleInt;

}

왜?

추신 : 분명하게 밝혀지면 미안합니다. 하지만 지금은 나와 함께 컴파일러가 없습니다 …



답변

예, ToList새 목록을 작성하지만이 경우 MyObject참조 유형 이므로 새 목록에는 원래 목록과 동일한 오브젝트에 대한 참조가 포함됩니다.

SimpleInt새 목록에서 참조 된 개체 의 속성을 업데이트하면 원래 목록의 해당 개체에도 영향을줍니다.

( MyObjectstruct아니라 선언 된 경우 class새 목록에는 원래 목록의 요소 사본이 포함되며 새 목록의 요소 특성을 업데이트 해도 원래 목록의 동등한 요소 에는 영향을 미치지 않습니다 .)


답변

반사판 소스에서 :

public static List<TSource> ToList<TSource>(this IEnumerable<TSource> source)
{
    if (source == null)
    {
        throw Error.ArgumentNull("source");
    }
    return new List<TSource>(source);
}

따라서 원본 목록은 업데이트되지 않지만 (추가 또는 제거) 참조 된 개체는 업데이트됩니다.


답변

ToList 컬렉션에 대한 후속 변경 사항을 반영하지 않는 새 목록을 항상 만듭니다.

그러나 객체 자체의 변경 사항을 반영합니다 (변경 가능한 구조체가 아닌 한).

즉, 원래 목록의 개체를 다른 개체로 ToList바꾸면 여전히 첫 번째 개체가 포함됩니다.
그러나 원래 목록에서 객체 중 하나를 수정해도 ToList동일한 (수정 된) 객체가 포함됩니다.


답변

수락 된 답변은 그의 사례를 바탕으로 OP의 질문을 올바르게 해결합니다. 그러나 ToList콘크리트 수집에 적용 되는 경우에만 적용됩니다 . 소스 시퀀스의 요소가 아직 인스턴스화되지 않은 경우 (지연된 실행으로 인해) 유지되지 않습니다. 후자의 경우, 호출 할 때마다 ToList(또는 순서를 열거 할 때마다) 새 항목 세트를 얻을 수 있습니다 .

다음은이 동작을 보여주기 위해 OP 코드를 수정 한 것입니다.

public static void RunChangeList()
{
    var objs = Enumerable.Range(0, 10).Select(_ => new MyObject() { SimpleInt = 0 });
    var whatInt = ChangeToList(objs);   // whatInt gets 0
}

public static int ChangeToList(IEnumerable<MyObject> objects)
{
    var objectList = objects.ToList();
    objectList.First().SimpleInt = 5;
    return objects.First().SimpleInt;
}

위의 코드가 고안된 것처럼 보이지만이 동작은 다른 시나리오에서는 미묘한 버그로 나타날 수 있습니다. 작업이 반복적으로 발생하는 상황에 대해서는 다른 예 를 참조하십시오 .


답변

예, 새 목록을 만듭니다. 이것은 의도적으로 설계된 동작입니다.

이 목록에는 원래 열거 가능한 시퀀스와 동일한 결과가 포함 되지만 영구적 인 (메모리 내) 컬렉션으로 구체화됩니다. 이를 통해 시퀀스 재 계산 비용을 발생시키지 않고 결과를 여러 번 사용할 수 있습니다.

LINQ 시퀀스의 장점은 합성 가능하다는 것입니다. 종종 IEnumerable<T>여러 필터링, 순서 및 / 또는 프로젝션 작업을 결합한 결과가 나타납니다. 확장 같은 방법 ToList()ToArray()당신이 표준 모음으로 계산 된 순서를 변환 할 수 있습니다.


답변

새 목록이 작성되지만 그 목록의 항목은 원래 목록과 마찬가지로 원래 항목에 대한 참조입니다. 목록 자체에 대한 변경은 독립적이지만 항목에 대한 변경은 두 목록에서 모두 변경됩니다.


답변

이 오래된 게시물을 우연히 발견하고 내 2 센트를 추가 할 생각이었습니다. 일반적으로 의심스러운 경우 모든 개체에서 GetHashCode () 메서드를 사용하여 ID를 확인합니다. 그래서 위의-

    public class MyObject
{
    public int SimpleInt { get; set; }
}


class Program
{

    public static void RunChangeList()
    {
        var objs = new List<MyObject>() { new MyObject() { SimpleInt = 0 } };
        Console.WriteLine("objs: {0}", objs.GetHashCode());
        Console.WriteLine("objs[0]: {0}", objs[0].GetHashCode());
        var whatInt = ChangeToList(objs);
        Console.WriteLine("whatInt: {0}", whatInt.GetHashCode());
    }

    public static int ChangeToList(List<MyObject> objects)
    {
        Console.WriteLine("objects: {0}", objects.GetHashCode());
        Console.WriteLine("objects[0]: {0}", objects[0].GetHashCode());
        var objectList = objects.ToList();
        Console.WriteLine("objectList: {0}", objectList.GetHashCode());
        Console.WriteLine("objectList[0]: {0}", objectList[0].GetHashCode());
        objectList[0].SimpleInt = 5;
        return objects[0].SimpleInt;

    }

    private static void Main(string[] args)
    {
        RunChangeList();
        Console.ReadLine();
    }

그리고 내 컴퓨터에 대답하십시오-

  • 목표 : 45653674
  • 목표 [0] : 41149443
  • 사물 : 45653674
  • 객체 [0] : 41149443
  • objectList : 39785641
  • objectList [0] : 41149443
  • whatInt : 5

따라서 본질적으로 목록이 전달하는 객체는 위 코드에서 동일하게 유지됩니다. 접근 방식이 도움이되기를 바랍니다.