订购时列表变空

时间:2013-09-09 16:26:47

标签: c# linq

我有以下方法:

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

哪个会返回数据。如果我做以下事情;

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

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

我很困惑为什么。

2 个答案:

答案 0 :(得分:4)

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

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

当您在属性获取器中使用ToList时,您正在获取列表的副本,而不仅仅是将引用复制到它,因此它基本上是该时刻的快照。当你获得属性时,列表显然是空的,但当你迭代它时,它显然不是。

如果两者都具有延迟执行的能力,并且始终根据调用者未手动应用的排序访问此属性中的项目,那么您可以使用以下内容:

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

也就是说,如果在访问时总是对集合进行排序是很重要的,那么将项目简单地存储在已排序的庄园中可能是优选的,因此访问这些项目是便宜的。请考虑使用类似SortedSet而非List的内容。

答案 1 :(得分:2)

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

所以当你打电话时:

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方法代替OrderBy LINQ扩展方法:

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

但要明确说明:你应该高度考虑,拥有这种财产的整体想法是错误的。你需要对你的数据进行排序吗?使用适当的数据结构,例如SortedList<int, Vehicle>而不是每次触发属性获取器时排序的标准List