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

Ram*_*uri 0 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) {}
}
Run Code Online (Sandbox Code Playgroud)

还有一个包含Person对象集合的类:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我想尝试创建一个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 });
Run Code Online (Sandbox Code Playgroud)

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

Jon*_*eet 7

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

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

public IEnumerator<Person> GetEnumerator()
{
    return GetEnumerator();
}
Run Code Online (Sandbox Code Playgroud)

该方法是递归的.您可能期望它调用显式接口实现,但它不是 - 它只是递归.

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

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();
}
Run Code Online (Sandbox Code Playgroud)

基本上,如果您只使用正常foreach循环,您会看到相同的效果:

foreach (var person in people)
{
    // You'd never get this far
}
Run Code Online (Sandbox Code Playgroud)

它与LINQ无关.