在IEnumerable集合上调用Enumerable.Join会导致分段错误

时间:2014-08-13 20:35:08

标签: c# linq ienumerable

我有一个人类:

public class Person
{
    public string Name {get; set;}
    public string Surname {get; set;}
    public uint Age {get; set;}

    public Person(string name, string surname, uint age)
    {
        Name= name; 
        Surname= surname;
        Age= age;
    }
    public Person() : this("default","default",25) {}
}

包含Person对象集合的类People:

public class People : IEnumerable<Person>
{
    private List<Person> people= new List<Person> ();
    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        people.GetEnumerator();
    }
    public IEnumerator<Person> GetEnumerator()
    {
        return GetEnumerator();
    }
    public void Add(Person p)
    {
        people.Add(p);
    }
}

现在我想尝试创建一个LINQ连接查询,它尝试对具有相同Name属性的人进行分组,创建一个包含该名称的新匿名对象,以及两个姓氏(Surname1,Surname2):

People ppl1 = new People() {
                new Person(),
                new Person("Mario","",35),
                new Person("Garcya","Luis",32)
            };
People ppl2 = new People() {
                new Person(),
                new Person("Pablo","Escobar",82),
                new Person("Claudio","Sevilla",33),
                new Person("Garcya","",31)
            };
var commonPpl=ppl1.Join<Person, Person, string, object>(ppl2, p => p.Name, p => p.Name,
                (p1, p2) => new { Name = p1.Name, Surname1 = p1.Surname, Surname2 = p2.Surname });

现在的问题是,如果我执行此查询,我会遇到一个分段错误:GetEnumerator()被无限调用,直到堆栈已满。

1 个答案:

答案 0 :(得分:7)

  

所以我可以想象Linq多次调用GetEnumerator()

不,事实并非如此。问题在于IEnumerable的实施,特别是在这里:

public IEnumerator<Person> GetEnumerator()
{
    return GetEnumerator();
}

该方法是递归的。你可能期待它来调用显式接口实现,但它不是 - 它只是递归。

通常,您使显式接口实现调用公共方法:

System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
    // Call the public method. The body of this method wasn't even valid before,
    // as it was calling `people.GetEnumerator() but not returning anything.
    return GetEnumerator();
}

public IEnumerator<Person> GetEnumerator()
{
    return people.GetEnumerator();
}

基本上,如果您使用普通foreach循环,您已经看到了同样的效果:

foreach (var person in people)
{
    // You'd never get this far
}

它与LINQ无关。