无法弄清楚为什么集合对bool属性返回false?

时间:2014-05-10 18:43:14

标签: c# lambda

我正在运行以下表达式,以根据Id获取2个集合之间的增量,并确保整体结果仅包含“有效/已启用”记录:

//Returns the right records but all IsEnabled = false
var newRecords = allRecordsFromA.Where(a => !(allRecordsFromB.Any(b => ((b.Id == a.Id) && a.IsEnabled)))).ToList();

上述结果会返回A中不在B中的所有正确记录,但所有记录都标记为IsEnabled = false。真正令人困惑的部分是我在应用程序的另一部分中的其他2个集合上使用 exact 相同的表达式,并且工作。我收回所有正确的记录,它们都被标记为.IsEnabled == true这对我来说毫无意义。我甚至复制了它并且它不起作用。

但是,如果我改为两步过程,我会得到我想要的结果:

//Works
var newRecords = allRecordsFromA.Where(a => !(allRecordsFromB.Any(b => (b.Id == a.Id)))).ToList();
var results = newRecords.Where(x => x.IsEnabled).ToList();

我在想第一个表达式中的操作顺序是错误的,返回记录时!被应用于IsEnabled但我看不到它。我的第一个表达式中返回带有IsEnabled == false的记录的错误是什么?

3 个答案:

答案 0 :(得分:3)

我认为你的括号不在你认为的位置。具体来说,a.IsEnabled位于Any语句中,然后被否定。

allRecordsFromB.Any(b => ((b.Id == a.Id) && a.IsEnabled))

这为您提供了与第二个示例完全不同的逻辑。我将a.IsEnabled移到Where的开头,删除一些不必要的括号以澄清事情。

var newRecords = allRecordsFromA.Where(a => a.IsEnabled &&
                       !allRecordsFromB.Any(b => b.Id == a.Id)).ToList();

请注意,如果您拥有大型数据集,或者认为以下方法更清晰,则可以通过创建b.Id的哈希集来加快速度。 (或通过某种类型的联接,内部会做同样的事情)

var bIds = new HashSet<int>(allRecordsFromB.Select(b => b.Id));
var newRecords = allRecordsFromA.Where(a => a.IsEnabled &&
                                            !bIds.Contains(a.Id)).ToList();

答案 1 :(得分:2)

检查a是否已启用在Any内,即否定。因此,如果条件b.Id == a.Idb)和allRecordsFromB中的某些a.IsEnabled条件都为真,那么该元素将成为结果的一部分。如果其中一个是假的,它将成为结果的一部分。

因为这与您想要的相反,您应该将IsEnabled支票移到Any.

之外

答案 2 :(得分:1)

我认为问题的一部分是你的Linq声明难以阅读而且这种目的无法实现。你可能想要考虑这样的事情:

var collectionA = new List<Record>();
var collectionB = new List<Record>();
var results = collectionA.Intersect(collectionB).Where(x => x.IsEnabled);

您必须实现Equals方法:

public class Record
{
    public int Id { get; set; }
    public bool IsEnabled { get; set; }

    protected bool Equals(Record other)
    {
        return Id == other.Id;
    }

    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj)) return false;
        if (ReferenceEquals(this, obj)) return true;
        if (obj.GetType() != this.GetType()) return false;
        return Equals((Record) obj);
    }

    public override int GetHashCode()
    {
        return Id;
    }
}

或者创建一个Comparer并将其传递给Intersect方法:

public class RecordComparer : IEqualityComparer<Record>
{
    public bool Equals(Record x, Record y)
    {
        return x.Id == y.Id;
    }

    public int GetHashCode(Record obj)
    {
        return obj.GetHashCode();
    }
}