C# 对可枚举项调用.ToArray会损坏可枚举项

C# 对可枚举项调用.ToArray会损坏可枚举项,c#,linq,ml.net,C#,Linq,Ml.net,我不确定这是否是特定于ML.NET的,但它确实是在它的上下文中发生的 我正在使用ML.NET对一些图像进行分类。我意识到,无论我是否调用生成的IEnumerable上的.ToArray(),都会造成严重的差异。前者导致所有数组元素与最后一个相同 IEnumerable<ImageData> dataCollection = imagePaths.Select(path => new ImageData(path)); IDataView targetDataView = _ml

我不确定这是否是特定于ML.NET的,但它确实是在它的上下文中发生的

我正在使用ML.NET对一些图像进行分类。我意识到,无论我是否调用生成的
IEnumerable
上的
.ToArray()
,都会造成严重的差异。前者导致所有数组元素与最后一个相同

IEnumerable<ImageData> dataCollection = imagePaths.Select(path => new ImageData(path));
IDataView targetDataView = _mlContext.Data.LoadFromEnumerable(dataCollection);
IDataView predictionView = _transformerModel.Transform(targetDataView); 
return _mlContext.Data.CreateEnumerable<ImagePrediction>(predictionView, true).ToArray();
IEnumerable dataCollection=imagepath.Select(path=>newimagedata(path));
IDataView targetDataView=mlContext.Data.LoadFromEnumerable(数据收集);
IDataView predictionView=_transformerModel.Transform(targetDataView);
返回mlContext.Data.CreateEnumerable(predictionView,true).ToArray();
在上面显示的示例中,生成的预测都将其图像路径设置为
imagepath
中的最后一个图像路径


我不相信这是故意的行为。这是什么原因造成的?我怎样才能安全地预防?目前,我决定不调用
.ToArray()
,但我想了解更多有关此问题的信息。

问题似乎在于预测引擎中限制内存使用的地方,
按照
重用对象
重用。因此,当调用
ToList()
ToArray()
方法时,只有最后一项用于投影列表/数组

public IEnumerable RunPipe(布尔重用对象)
{
var curCounter=_计数器;
使用(var cursor=\u cursorablePipe.GetCursor())
{
TDst行=空;
while(cursor.MoveNext())
{
如果(!reuseRowObject | | row==null)
行=新的TDst();
cursor.FillValues(行);
收益返回行;
如果(curCounter!=\u计数器)
抛出契约。除了(“试图在管道重置后继续迭代”);
}
}
}
调用方是
CreateEnumerable()
,您可以在其中显式地将
reuseRowObject
设置为
true

public IEnumerable CreateEnumerable(IDataView数据,布尔重用对象,
bool ignoreMissingColumns=false,SchemaDefinition SchemaDefinition=null)
其中TRow:class,new()
{
_环境检查值(数据、名称(数据));
_环境检查值或完整(方案定义);
var engine=新管道引擎(_env,data,ignoreMissingColumns,schemaDefinition);
返回发动机。运行管(再利用项目);
}

reuseRowObject
设置为
false
应该可以解决您的问题。

使用
ToList()
是否也会出现这种行为?@Yennefer是的,确实会。奇怪的是,我在代码后面使用了
Select
子句进一步使用了
IEnumerable
,如果我以前不将其转换为数组,它就不会出现问题。通常,发生这种情况时,是由于对重用的对象实例的闭包。因此,延迟可枚举项的执行只会生成最后一项。什么是
\mlContext.Data.CreateEnumerable(predictionView,true)
GetType()
?@Yennefer类型是
Microsoft.ML.PipeEngine`1+d_uu3[Application.ImagePrediction]
。由于需要更多的关注点,对投票关闭该问题的人来说:该问题缺少关注点在哪里?它询问为什么数组被
.ToArray()
损坏,Yennefer用他们的答案简洁地解释了这一点。如果你仍然认为我可以更好地表达这个问题,我很乐意接受你的反馈!这很有道理!我真的应该停止把
IEnumerable
s看作数组或列表之类的隐式容器。因此,基本上,
reuseRowObject
最大限度地减少了内存使用,但代价是无法将生成的可枚举项转换为集合?从某种意义上说,是的。这取决于数据的使用方式:当对象被重用时,它会被多次生成,但“它所引用的值”在幕后正在发生变化。因此,在构建集合时,从技术上讲,它反复包含相同的实例。在高性能代码上,这个技巧是必要的,因为恒定的分配会给GC增加压力并减慢代码的速度,但这意味着您会立即使用返回的值。如果您想拥有一个集合,此优化对您不利。