IEnumerable< T>直到Count()或Any()被调用才有结果

本文关键字:调用 结果 Any 直到 Count IEnumerable | 更新日期: 2023-09-27 17:53:54

我正在测试Linq扩展方法的性能变化,并且我遇到了一个奇怪的情况。

当执行返回到测试时,首先调用Count()将返回1,随后的Any()为false。

当首先调用Any()时,它为真,随后的Count()为0。

在调用任何方法之前的断点检查都显示有一个项目是预期的,但是在以这种方式或调用Any()或Count()枚举之后,可枚举对象为空。

有人能解释一下这种行为吗?由于延迟执行的一些警告,在我的实现中是否存在错误?
public class Thing
{
    public Guid Id { get; set; }
}
[TestClass]
public class IEnumerableExtensionsTests
{
    Guid[] thingKeys = new Guid[1] { Guid.Parse("11A1AA1A-1A11-A111-AA11-111111AA1A11") };
    System.Collections.ObjectModel.Collection<Thing> things= new System.Collections.ObjectModel.Collection<Thing>();
    int additionalThingCount = 100;
    [TestMethod]
    public void TestIntersect1()
    {
        DateTime start = DateTime.Now;
        var exceptionsList = things.Intersect1(thingKeys, (e) => e.Id);
        //int count1 = exceptionsList.Count();
        //Assert.AreEqual<int>(thingKeys.Length, count1);
        bool any1 = exceptionsList.Any();
        int count2 = exceptionsList.Count();
        bool any2 = exceptionsList.Any();
        string key = thingKeys[0].ToString();
        var first = exceptionsList.FirstOrDefault();
        var result = exceptionsList.FirstOrDefault(e => e.Id.ToString() == key);
        var duration = DateTime.Now - start;
        Debug.WriteLine(string.Format("TestIntersect1 duration {0}", duration));
        Assert.IsNotNull(result);
    }
    [TestInitialize]
    public void TestInit()
    {
        foreach(var key in thingKeys)
        {
            things.Add(new Thing()
            {
                Id = key
            });
        };
        for (int i1 = 0; i1 < additionalThingCount; i1++)
        {
            things.Add(new Thing()
            {
                Id = Guid.NewGuid()
            });
        }
    }
}
public static class IEnumerableExtension
{
    public static IEnumerable<T> Intersect1<T, Y>(this IEnumerable<T> items, IEnumerable<Y> keys, Func<T, Y> firstMemberSelector)
    {
        var hashset = new HashSet<Y>(keys);
        var returnValue = items.Where(t => hashset.Remove(firstMemberSelector(t)));
        return returnValue;
    }
}

IEnumerable< T>直到Count()或Any()被调用才有结果

每次迭代结果时,您将调用该Where过滤器…其中在进入时从hashset中删除项。

所以在迭代一次之后,hashset将不再有任何这些项,所以没有任何东西可以返回。

基本上,您所观察到的是具有副作用的Where子句是一个坏主意。

您可能需要使用Join来执行交集:

return items.Join(keys, firstMemberSelector, key => key, (value, key) => value);

与不完全相同,因为它不是一个集合操作…但是你可以解决这个问题