수업이 있다고 가정 해 봅시다
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
새 목록에서 참조 된 개체 의 속성을 업데이트하면 원래 목록의 해당 개체에도 영향을줍니다.
( MyObject
가 struct
아니라 선언 된 경우 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
따라서 본질적으로 목록이 전달하는 객체는 위 코드에서 동일하게 유지됩니다. 접근 방식이 도움이되기를 바랍니다.