0

我有以下方法:

    public List<Vehicle> Vehicles
    {
        get { return _vehicles; }
    }

这将返回数据。如果我执行以下操作;

    public List<Vehicle> Vehicles
    {
        get { return _vehicles.OrderBy(v => v.Year).ToList(); }
    }

它变成空的。如果我在此方法之外调用 orderby myList = vehicleList.Vehicles.OrderBy(x => x.Year),则列表将包含所有需要的数据。

我很困惑为什么。

4

2 回答 2

4

在第一种情况下,您返回的是对列表的引用,而不是列表的副本。如果稍后修改内部列表,则外部列表将能够观察到这些更改(因为它毕竟是同一个列表)。

当您OrderBy从列表之外使用 LINQ 的方法时,它将推迟执行。直到您实际迭代该序列的结果,它才会进入并查看列表;在这一点上很可能已经改变了。

当您ToList在属性 getter 中使用时,您正在获取列表的副本,而不仅仅是复制对它的引用,因此它基本上是那个时刻的快照。在您获得该属性时,列表 [显然] 是空的,但是当您对其进行迭代时,它 [显然] 不是。

如果两者都具有延迟执行的能力很重要,并且始终基于调用者未手动应用的排序来访问此属性中的项目,那么您可以使用类似这样的东西:

public IEnumerable<Vehicle> Vehicles
{
    get { return _vehicles.OrderBy(v => v.Year); }
}

也就是说,如果在访问时始终对集合进行排序很重要,那么最好将项目简单地存储在排序的庄园中,以便访问这些项目很便宜。考虑使用类似 aSortedSet而不是 a 的东西List

于 2013-09-09T16:37:18.913 回答
2

我认为您错过了一个事实,即ToList()创建新List<T>的而不是返回基础的。

所以当你打电话时:

var list = vehicleList.Vehicles;
list.Add(new Vehicle());
list.Add(new Vehicle());
Console.WriteLine(vehicleList.Vehicles.Count);

它将2为您的第一个Vehicles财产声明和0第二个财产声明打印。

那是因为在您的第二个属性声明中,您将项目添加到List刚刚使用ToList()调用创建的项目,而不是来自_vehicles支持字段的项目。

要使其工作,请尝试以下操作:

public List<Vehicle> Vehicles
{
    get { return (_vehicles = _vehicles.OrderBy(v => v.Year).ToList()); }
}

或者使用List<T>.Sort方法而不是OrderByLINQ 扩展方法:

public List<Vehicle> Vehicles
{
    get
    {
        _vehicles.Sort((v1, v2) => v1.Year.CompareTo(v2.Year));
        return _vehicles;
    }
}

但要明确一点:您应该高度考虑,拥有这种财产的总体想法是错误的。您需要始终对数据进行排序吗?使用适当的数据结构,而不是每次触发属性 getter 时排序SortedList<int, Vehicle>的标准。List

于 2013-09-09T16:40:57.633 回答