`Where`子句返回空列表,即使逻辑测试是'true`

时间:2017-02-10 10:00:51

标签: c# linq mvvm where caliburn.micro

我需要显示满足某些条件的项目。

public BindableCollection<BaseTreeItemViewModel> TreeItems
{
    get
    {
        if (_logicTest)
            return (BindableCollection<BaseTreeItemViewModel>)_treeItems.Where(n => _logicTest);
        else
            return _treeItems;
    }
    set
    {
        _treeItems = value;
        NotifyOfPropertyChange(() => TreeItems);
    }
}

事实上在Where子句中会有不同的测试(n.Header == "ABC"),但即使对于_logicTest它也不起作用,我们知道true在启动时与Where对齐。

_treeItems包含大约20个元素,对于_logicTest=false,它们都返回。另一方面,_logicTest=true函数返回空集合。

错误在哪里?

提前感谢您的帮助。

修改

作为@ Robert.S suggested,我使用过:

return new BindableCollection<BaseTreeItemViewModel>(_treeItems.Where(n => _logicTest));

它有效。感谢。

1 个答案:

答案 0 :(得分:3)

什么是_logicTest?一个属性?如果是这样,它可能会在评估集合时发生变化。此外,Where的返回值为IEnumerable<T>。只有在使用集合时才会评估实际值(例如,在foreach循环中)。

您可以尝试在ToList()的末尾添加ToArray()Where。这样就可以立即评估集合,并且可以看到在执行getter的时候是否真的没有项目。

另一个选项是VS调试器。在监视表中,您可以使用小刷新图标评估集合。这样你也可以看到真实的&#34;项目

但是如果您稍后使用该集合(例如在foreach循环中)并且_logicTest不再是真的,则该集合可能为空。

这是一个简单的例子:

class Program
{
    static bool _logicTest = false;
    static int[] items = new int[] { 1, 2, 3 };

    static void Main(string[] args)
    {
        _logicTest = true;

        var foo = items.Where(n => _logicTest);

        _logicTest = false;

        Console.WriteLine(foo.Count());

        _logicTest = true;

        Console.WriteLine(foo.Count());
    }
}

输出将是: 0 3

在上面的示例中,Count()将评估集合以确定其大小。您可以看到_logicTest的值在此时评估,而不是在调用Where时评估。

您案例的可能解决方法是本地变量:

get
{
    bool logicTest = _logicTest;

    if (logicTest)
        return (BindableCollection<BaseTreeItemViewModel>)_treeItems.Where(n => logicTest);
    else
        return _treeItems;
}

局部变量不会改变。但是您应该将属性值存储在另一个变量中。如果您在_logicTest为假时访问该属性,则会遇到同样的问题。

以上是解决方法的上述示例:

class Program
{
    static bool _logicTest = false;
    static int[] items = new int[] { 1, 2, 3 };

    static void Main(string[] args)
    {
        _logicTest = true;

        var foo = items.Where(n => _logicTest);
        var bar = Items;

        _logicTest = false;

        Console.WriteLine(foo.Count());
        Console.WriteLine(bar.Count());

        _logicTest = true;

        Console.WriteLine(foo.Count());
        Console.WriteLine(bar.Count());
    }

    static IEnumerable<int> Items
    {
        get
        {
            bool logicTest = _logicTest;

            return items.Where(n => logicTest);
        }
    }
}

输出为0 3 3 3