ToList(Linq)似乎不会复制引用

时间:2015-09-05 08:00:13

标签: c# linq list reference ienumerable

我的代码看起来像这样:

var selectedItems = ItemList.SelectedItems().ToList();
var selectedItems2 = ItemList2.SelectedItems().ToList();
selectedItems[0] = selectedItems2[0];

在这里查看SelectedItems扩展方法:

public static IEnumerable<T> SelectedItems<T>(this IEnumerable<T> source) where T : ISelectable
{
    return source.Where(s => s.IsSelected);
}

每当我执行ReferenceEquals(ItemList, selectedItems)时,该值都会返回false,每当我修改任何列表中的值时,更改都不会反映在另一个列表中。

ItemList中的项目是引用类型(自定义类)。

我做错了什么?

编辑:

这是原始代码。我并不想让事情过于复杂,但在这里却是:

var test = Map.TileMap.Layers[0].TileList.SelectedItems().ToList();
if (ReferenceEquals(test[0], Map.TileMap.Layers[0].TileList[0]))
{
           // returns true     
}

var tileset2D = Tileset.TileMap.Layers[0].TileList.SelectedItems().To2D(t => t.SelectableRegion.Y).ToList();
test[0] = tileset2D[0][0];

// test[0] has changed but Tileset.TileMap.Layers[0].TileList[0] hasn't changed.

这是To2D扩展方法:

public static IEnumerable<IEnumerable<T>> To2D<T, TKey>(this IEnumerable<T> source, Func<T, TKey> keySelector)
{
    if (source == null)
    {
        throw new ArgumentNullException(nameof(source), "Source collection cannot be null");
    }

    return source.GroupBy(keySelector);
}

2 个答案:

答案 0 :(得分:1)

调用.ToList()不是强制转换操作。它会生成一个全新的列表对象,并使用.ToList()之前的可枚举结果填充它。引用不一样,因为它们是不同的列表。

SelectedItems方法应该返回原始列表的实例。所以你应该能够测试它是否有效。

使用此示例代码:

var ItemList = new List<Selectable>()
{
    new Selectable() { IsSelected = true },
    new Selectable() { IsSelected = false },
};

var selectedItems = ItemList.SelectedItems().ToList();

Console.WriteLine(selectedItems[0].IsSelected);

ItemList[0].IsSelected = false;

Console.WriteLine(selectedItems[0].IsSelected);

我得到了结果:

True
False

Selectable的实施是:

public class Selectable : ISelectable
{
    public bool IsSelected { get; set; }
}

您必须在未显示的代码中发生某些事情。

您已经添加了更多代码,现在snippit .GroupBy(t => t.SelectableRegion.Y)让我觉得分组没有按预期工作。您应该测试关于分组键返回的假设

此时我的建议是避免重新创建扩展方法。写source.Where(s => s.IsSelected).GroupBy(t => t.SelectableRegion.Y)source.SelectedItems().To2D(t => t.SelectableRegion.Y)更好。这种事情只会混淆代码并使其更难以推理。你经历的各种错误经常浮出水面。

答案 1 :(得分:0)

问题是我正在为我的列表项

分配一个新的引用
test[0] = tileset2D[0][0];

所以现在test [0]指向内存中与tileset2D [0] [0]相同的地址。这就是为什么test [0]中的值没有修改Map.TileMap.Layers [0] .TileList中的值的原因。

所以我基本上必须创建一些DeepClone方法,它将复制值并克隆引用,而不会为我的TileList项指定新的引用。

感谢所有帮助:)