【问题标题】:ToList (Linq) doesn't appear to copy referencesToList (Linq) 似乎没有复制引用
【发布时间】:2015-09-05 08:00:13
【问题描述】:

我的代码看起来像这样:

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);
}

【问题讨论】:

  • ItemList的来源是什么? IQueryable/List&lt;T&gt;/etc.?
  • 列表。 T 是 ISelectable。
  • 几乎听起来该列表已经由不同的实体构成。你确定过滤前的ReferenceEquals(ItemList[0], ItemList2[0]) == true

标签: c# linq list reference ienumerable


【解决方案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

我对@9​​87654326@ 的实现是:

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

你必须在你没有显示的代码中发生了一些事情。


您添加了更多代码,现在代码片段.GroupBy(t =&gt; t.SelectableRegion.Y) 让我认为分组没有按预期工作。您应该测试您对分组键返回什么的假设

在这一点上,我的建议是避免重新创建扩展方法。写source.Where(s =&gt; s.IsSelected).GroupBy(t =&gt; t.SelectableRegion.Y) 比写source.SelectedItems().To2D(t =&gt; t.SelectableRegion.Y) 更好。这种事情只会混淆代码并使其更难推理。您遇到的错误种类太频繁了。

【讨论】:

  • 但它不应该复制上一个列表中的引用吗?
  • 因为 ToList() 返回新的 List(source)
  • @Enigmativity 如何返回原始列表的实例?这不就是我使用 Where 所做的吗?
  • 这应该不会影响任何事情。我正在使用 GroupBy 的值分配给我的列表。即使我做了类似 Map.TileMap.Layers[0].TileList[0] = Tileset.TileMap.Layers[0].TileList[0] 之类的事情,它仍然不起作用。 test[0] 与 Map.TileMap.Layers[0].TileList[0] 不匹配,即使它们具有相同的引用。此外,当我分配一个值说 test[0] 时,引用会更改并且不再等于 Map.TileMap.Layers[0].TileList[0]
  • 好的,我做了一个快速测试,我的预感是正确的。我这样做了: Map.TileMap.Layers[0].TileList[0].Texture = Tileset.TileMap.Layers[0].TileList[0].Texture;它奏效了!因此,每当我只分配整个值时,都会更改参考。嗯
【解决方案2】:

问题是我正在为我的列表项分配一个新的引用

test[0] = tileset2D[0][0];

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

所以我基本上必须创建一些时间的 DeepClone 方法,该方法将复制值并克隆引用,而无需为我的 TileList 项分配新引用。

感谢大家的帮助:)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-09-11
    • 1970-01-01
    • 2016-10-15
    • 2011-05-01
    • 1970-01-01
    • 2011-11-03
    • 1970-01-01
    相关资源
    最近更新 更多