C# Linq的执行顺序是这次捕获的原因吗?

C# Linq的执行顺序是这次捕获的原因吗?,c#,linq,deferred-execution,C#,Linq,Deferred Execution,我有这个功能来重复一个序列: public static List<T> Repeat<T>(this IEnumerable<T> lst, int count) { if (count < 0) throw new ArgumentOutOfRangeException("count"); var ret = Enumerable.Empty<T>(); for (var i = 0; i &l

我有这个功能来重复一个序列:

public static List<T> Repeat<T>(this IEnumerable<T> lst, int count)
{
    if (count < 0)
        throw new ArgumentOutOfRangeException("count");

    var ret = Enumerable.Empty<T>();

    for (var i = 0; i < count; i++)
        ret = ret.Concat(lst);

    return ret.ToList();
}
我希望我是100岁,但它给了我1000岁!我的问题是,为什么会发生这种情况?Linq难道不应该足够聪明,知道这是我需要用变量
ret
连接的第一批选定的100个人吗?我感觉这里的
Concat
ret.ToList()
执行时,与
Select
一起使用时会被优先考虑

编辑:

如果我这样做,我会得到预期的正确结果:

var f = d.Select(t => new Person()).ToList().Repeat(10); 
int i = f.Distinct().Count(); //prints 100
再次编辑:


我没有重写
等于
。我只是想得到100个独特的人(当然是通过参考)。我的问题是,有人能向我解释一下为什么Linq不先执行select操作,然后再进行连接(当然是在执行时)?

每个
Person
对象都是一个单独的对象。所有1000个都是不同的


类型的平等定义是什么?如果不重写它,则该定义将是引用相等,这意味着所有1000个对象都是不同的。

每个
对象都是一个单独的对象。所有1000个都是不同的


类型的平等定义是什么?如果不重写它,则该定义将是引用相等,这意味着所有1000个对象都是不同的。

问题是,除非调用
ToList
,否则
d.Select(t=>new Person())
将在每次
Repeat
遍历列表时重新枚举,从而创建重复的
Person
s。这种技术被称为

通常,
LINQ
并不假设每次枚举一个序列时,它都会得到相同的序列,甚至是相同长度的序列。如果这种效果不理想,您可以通过立即调用
ToList
Repeat
方法中的序列“具体化”,如下所示:

public static List<T> Repeat<T>(this IEnumerable<T> lstEnum, int count) {
    if (count < 0)
        throw new ArgumentOutOfRangeException("count");

    var lst = lstEnum.ToList(); // Enumerate only once
    var ret = Enumerable.Empty<T>();

    for (var i = 0; i < count; i++)
        ret = ret.Concat(lst);

    return ret.ToList();
}
公共静态列表重复(此IEnumerable lstEnum,int count){
如果(计数<0)
抛出新ArgumentOutOfRangeException(“计数”);
var lst=lstEnum.ToList();//只枚举一次
var ret=Enumerable.Empty();
对于(变量i=0;i
问题在于,除非调用
ToList
,否则每次重复
时都会重新枚举
d.Select(t=>new Person())
,从而创建重复的
Person
s。这种技术被称为

通常,
LINQ
并不假设每次枚举一个序列时,它都会得到相同的序列,甚至是相同长度的序列。如果这种效果不理想,您可以通过立即调用
ToList
Repeat
方法中的序列“具体化”,如下所示:

public static List<T> Repeat<T>(this IEnumerable<T> lstEnum, int count) {
    if (count < 0)
        throw new ArgumentOutOfRangeException("count");

    var lst = lstEnum.ToList(); // Enumerate only once
    var ret = Enumerable.Empty<T>();

    for (var i = 0; i < count; i++)
        ret = ret.Concat(lst);

    return ret.ToList();
}
公共静态列表重复(此IEnumerable lstEnum,int count){
如果(计数<0)
抛出新ArgumentOutOfRangeException(“计数”);
var lst=lstEnum.ToList();//只枚举一次
var ret=Enumerable.Empty();
对于(变量i=0;i
我可以把我的问题分解成一些不那么琐碎的事情:

var d = Enumerable.Range(1, 100);
var f = d.Select(t => new Person());
现在我基本上是这样做的:

f = f.Concat(f);
注意,你的查询到现在还没有执行。执行时,
f
仍然是
d。选择(t=>newperson())
未执行。因此,执行时的最后一条语句可以分解为:

f = f.Concat(f); 
//which is 
f = d.Select(t => new Person()).Concat(d.Select(t => new Person()));
创建100+100=200个新的Person实例是显而易见的。所以

f.Distinct().ToList(); //yields 200, not 100
这是正确的行为

Edit:我可以简单地重写扩展方法,

public static IEnumerable<T> Repeat<T>(this IEnumerable<T> source, int times)
{
    source = source.ToArray();
    return Enumerable.Range(0, times).SelectMany(_ => source);
}
公共静态IEnumerable Repeat(此IEnumerable源,int次)
{
source=source.ToArray();
返回可枚举的范围(0,次)。选择many(=>source);
}

我利用dasblinkenlight的建议解决了这个问题。

我可以将我的问题分解为一些不那么琐碎的问题:

var d = Enumerable.Range(1, 100);
var f = d.Select(t => new Person());
现在我基本上是这样做的:

f = f.Concat(f);
注意,你的查询到现在还没有执行。执行时,
f
仍然是
d。选择(t=>newperson())
未执行。因此,执行时的最后一条语句可以分解为:

f = f.Concat(f); 
//which is 
f = d.Select(t => new Person()).Concat(d.Select(t => new Person()));
创建100+100=200个新的Person实例是显而易见的。所以

f.Distinct().ToList(); //yields 200, not 100
这是正确的行为

Edit:我可以简单地重写扩展方法,

public static IEnumerable<T> Repeat<T>(this IEnumerable<T> source, int times)
{
    source = source.ToArray();
    return Enumerable.Range(0, times).SelectMany(_ => source);
}
公共静态IEnumerable Repeat(此IEnumerable源,int次)
{
source=source.ToArray();
返回可枚举的范围(0,次)。选择many(=>source);
}

我使用dasblinkenlight的建议来解决这个问题。

@BrianRasmussen是的,但不同的计数仍然是100,对吗?Distint应用于包含1000个
个人
实例的列表。我假设
Person
是一个引用不相等的类。@BrianRasmussen是的,但不同的计数仍然是100对吗?Distint应用于包含1000个
Person
实例的列表。我假设
Person
是一个类,它们不相等。请参阅我的编辑。我明白。我的问题是为什么会这样。它肯定与LinqReference中的执行有关,因为我没有重写任何内容,所以函数正在检查的是等式。但是Linq把这当成1000个不同的物体,这不是很奇怪吗oSee我的编辑。我明白。我的问题是为什么会这样。它肯定与LinqReference中的执行有关,因为我没有重写任何内容,所以函数正在检查的是等式。但是Linq把这当成1000个不同的物体,这不是很奇怪吗哦,这是我想的唯一可能的解释。但最后你不认为这是一个错误!!我觉得