Digamos que eu tenho uma aula
public class MyObject
{
public int SimpleInt{get;set;}
}
E eu tenho um List<MyObject>
, e eu ToList()
, e depois altero um dos SimpleInt
, minha alteração será propagada de volta para a lista original. Em outras palavras, qual seria o resultado do método a seguir?
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;
}
Por quê?
P / S: Me desculpe se parece óbvio descobrir. Mas eu não tenho compilador comigo agora ...
.ToList()
fazer uma cópia superficial . As referências são copiadas, mas as novas referências ainda apontam para as mesmas instâncias que as referências originais apontam para. Quando você pensa sobre isso,ToList
não pode criar nenhumnew MyObject()
quandoMyObject
é umclass
tipo.Respostas:
Sim,
ToList
criará uma nova lista, mas porque neste casoMyObject
é um tipo de referência, a nova lista conterá referências aos mesmos objetos que a lista original.Atualizando o
SimpleInt
propriedade de um objeto mencionado na nova lista também afetará o objeto equivalente na lista original.(Se
MyObject
fosse declarado como umstruct
e não umclass
, a nova lista conteria cópias dos elementos na lista original e a atualização de uma propriedade de um elemento na nova lista não afetaria o elemento equivalente na lista original.)fonte
List
das estruturas, uma atribuição comoobjectList[0].SimpleInt=5
não seria permitida (erro em tempo de compilação em C #). Isso ocorre porque o valor de retorno doget
acessador do indexador de lista não é uma variável (é uma cópia retornada de um valor de struct) e, portanto, a configuração de seu membro.SimpleInt
com uma expressão de atribuição não é permitida (isso mudaria uma cópia que não é mantida) . Bem, quem usa estruturas mutáveis, afinal?foreach (var s in listOfStructs) { s.SimpleInt = 42; }
. A pegadinha realmente desagradável é quando você tenta algo comolistOfStructs.ForEach(s => s.SimpleInt = 42)
: o compilador permite e o código é executado sem exceções, mas as estruturas da lista permanecerão inalteradas!Da fonte do Refletor:
Portanto, sim, sua lista original não será atualizada (por exemplo, adições ou remoções), mas os objetos referenciados serão.
fonte
ToList
sempre criará uma nova lista, que não refletirá nenhuma alteração subsequente na coleção.No entanto, ele refletirá alterações nos próprios objetos (a menos que sejam estruturas mutáveis).
Em outras palavras, se você substituir um objeto na lista original por um objeto diferente,
ToList
ele ainda conterá o primeiro objeto.No entanto, se você modificar um dos objetos na lista original,
ToList
ele ainda conterá o mesmo objeto (modificado).fonte
A resposta aceita aborda corretamente a pergunta do OP com base em seu exemplo. No entanto, isso só se aplica quando
ToList
aplicado a uma coleção concreta; não é válido quando os elementos da sequência de origem ainda não foram instanciados (devido à execução adiada). No caso deste último, você poderá obter um novo conjunto de itens sempre que ligarToList
(ou enumerar a sequência).Aqui está uma adaptação do código do OP para demonstrar esse comportamento:
Embora o código acima possa parecer artificial, esse comportamento pode aparecer como um bug sutil em outros cenários. Veja meu outro exemplo para uma situação em que faz com que as tarefas sejam geradas repetidamente.
fonte
Sim, ele cria uma nova lista. Isso ocorre por design.
A lista conterá os mesmos resultados que a sequência enumerável original, mas materializada em uma coleção persistente (na memória). Isso permite consumir os resultados várias vezes, sem incorrer no custo de recalcular a sequência.
A beleza das sequências LINQ é que elas são compostas. Freqüentemente,
IEnumerable<T>
você obtém o resultado da combinação de várias operações de filtragem, pedido e / ou projeção. Os métodos de extensão gostamToList()
eToArray()
permitem converter a sequência computada em uma coleção padrão.fonte
Uma nova lista é criada, mas os itens nela são referências aos itens originais (assim como na lista original). As alterações na lista em si são independentes, mas nos itens a alteração será encontrada nas duas listas.
fonte
Apenas tropeçar neste post antigo e pensei em adicionar meus dois centavos. Geralmente, em caso de dúvida, uso rapidamente o método GetHashCode () em qualquer objeto para verificar as identidades. Então, para cima -
E responda na minha máquina -
Portanto, essencialmente o objeto que a lista carrega permanece o mesmo no código acima. Espero que a abordagem ajude.
fonte
Eu acho que isso equivale a perguntar se o ToList faz uma cópia profunda ou superficial. Como o ToList não tem como clonar o MyObject, ele deve fazer uma cópia superficial; portanto, a lista criada contém as mesmas referências que a original; portanto, o código retorna 5.
fonte
ToList
criará uma nova lista.Se os itens na lista forem tipos de valor, eles serão atualizados diretamente; se forem tipos de referência, quaisquer alterações serão refletidas nos objetos referenciados.
fonte
No caso em que o objeto de origem é um IEnumerable verdadeiro (ou seja, não apenas uma coleção empacotada como enumerável), ToList () NÃO pode retornar as mesmas referências de objeto que no IEnumerable original. Ele retornará uma nova lista de objetos, mas esses objetos podem não ser iguais ou iguais aos objetos produzidos pelo IEnumerable quando forem enumerados novamente
fonte
Isso também atualizará o objeto original. A nova lista conterá referências aos objetos contidos nela, assim como a lista original. Você pode alterar os elementos e a atualização será refletida no outro.
Agora, se você atualizar uma lista (adicionando ou excluindo um item) que não será refletida na outra lista.
fonte
Não vejo em nenhum lugar da documentação que ToList () esteja sempre garantido para retornar uma nova lista. Se um IEnumerable é uma lista, pode ser mais eficiente verificar isso e simplesmente retornar a mesma lista.
A preocupação é que, às vezes, você queira ter certeza absoluta de que a lista retornada é! = Para a lista original. Como a Microsoft não documenta que o ToList retornará uma nova lista, não podemos ter certeza (a menos que alguém tenha encontrado essa documentação). Também pode mudar no futuro, mesmo que funcione agora.
nova lista (IEnumerable enumerablestuff) é garantida para retornar uma nova lista. Eu usaria isso em seu lugar.
fonte
ToList
pareça criar uma nova referência de objeto de lista quando chamada em umList
, BenB está certo quando diz que isso não é garantido pela documentação da MS.IEnumerable<>.ToList()
é realmente implementado comonew List<>(source)
e não há substituição específica paraList<>
; portanto,List<>.ToList()
ele realmente retorna uma nova referência de objeto de lista. Mas, mais uma vez, conforme a documentação da MS, não há garantia de que isso não mude no futuro, embora provavelmente interrompa a maior parte do código existente.