Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 事件委托在foreach循环中添加后消失_C#_Linq_Events - Fatal编程技术网

C# 事件委托在foreach循环中添加后消失

C# 事件委托在foreach循环中添加后消失,c#,linq,events,C#,Linq,Events,我正在尝试将事件委托添加到列表中的对象中。在下面的示例中,我想在对象触发关联事件时添加恐龙委托。我将它们添加到一个foreach循环中,但不知何故,它们会立即消失 class MyViewModel { MyViewModel(List<Dinosaur> dinosaurs) { // This works and creates the ViewModel the way I expect it to: m_dinosaurs =

我正在尝试将事件委托添加到列表中的对象中。在下面的示例中,我想在对象触发关联事件时添加
恐龙
委托。我将它们添加到一个
foreach
循环中,但不知何故,它们会立即消失

class MyViewModel
{
    MyViewModel(List<Dinosaur> dinosaurs)
    {
        // This works and creates the ViewModel the way I expect it to:
        m_dinosaurs = dinosaurs.Select( x => new DinosaurViewModel(x) );

        foreach (DinosaurViewModel dino in m_dinosaurs)
        {
            // This works within the scope of the loop
            dino.Jumped += dinosaur_Jumped;
        }

        // But now all my Jumped delegates are suddenly all gone
    }

    void dinosaur_Jumped(object sender, JumpingEventArgs e)
    {
        // This never gets called, even when the events do fire:
        Console.WriteLine("A dinosaur jumped");
    }

    private IEnumerable<DinosaurViewModel> m_dinosaurs;
}
类MyViewModel
{
MyViewModel(列出恐龙)
{
//这将按照我期望的方式工作并创建ViewModel:
m_恐龙=恐龙。选择(x=>新恐龙视图模型(x));
foreach(恐龙视图m_恐龙中的恐龙模型)
{
//这在循环的范围内工作
恐龙跳跃+=恐龙跳跃;
}
//但现在我所有的代表突然都不见了
}
无效恐龙_跳跃(对象发送器,跳跃事件参数e)
{
//即使发生以下事件,也不会调用此命令:
控制台。WriteLine(“一只恐龙跳了起来”);
}
私人可数恐龙;
}

我认为这与不正确的作用域/闭包或其他东西有关;将委托添加到立即超出范围的变量(在本例中为
dino
)中,但我不知道如何才能做到这一点。为什么不起作用?

因为我看不出您是如何检查您的
跳过的
代理的,所以我假设您正在执行
m_恐龙的后续迭代

由于
Select
是惰性的,任何后续迭代都将导致创建不同的
viewmodel
实例,这意味着您将检查添加了事件处理程序的不同实例

解决这个问题的一个方法是将集合物化,例如

m_dinosaurs = dinosaurs.Select( x => new DinosaurViewModel(x) ).ToList();
可能的垃圾收集

垃圾收集器会导致一种不太可能但可能的情况,您的
Select
语句将为每个迭代创建一个新的
viewmodel
,当您迭代
m_digoros
并添加事件处理程序时,新创建的
digoraviewmodel
将符合垃圾收集的条件,因为没有保留对它的引用


解决方案是确保您保留对每个创建的
恐龙视图模型的引用,与
相同的解决方案就足够了。ToList()
调用将确保保留对每个创建的
恐龙视图模型的引用,这意味着他们不再有资格进行垃圾收集。

因为我看不出您是如何检查您的
跳过的
代理的,所以我假设您正在执行
m_恐龙的后续迭代

由于
Select
是惰性的,任何后续迭代都将导致创建不同的
viewmodel
实例,这意味着您将检查添加了事件处理程序的不同实例

解决这个问题的一个方法是将集合物化,例如

m_dinosaurs = dinosaurs.Select( x => new DinosaurViewModel(x) ).ToList();
可能的垃圾收集

垃圾收集器会导致一种不太可能但可能的情况,您的
Select
语句将为每个迭代创建一个新的
viewmodel
,当您迭代
m_digoros
并添加事件处理程序时,新创建的
digoraviewmodel
将符合垃圾收集的条件,因为没有保留对它的引用


解决方案是确保您保留对每个创建的
恐龙视图模型的引用,与
相同的解决方案就足够了。ToList()
调用将确保保留对每个创建的
恐龙视图模型的引用,这意味着它们不再有资格进行垃圾收集。

可枚举。Select
是惰性的。非常懒。事实上,它是如此懒惰,以至于完全忽略了您已经从中看到的任何输出。当你第二次迭代
m_恐龙
时,你会得到一批全新的
恐龙模型
对象


您可以使用
恐龙.ConvertAll(x=>新恐龙视图模型(x))
将模型存储在列表中。

可枚举。选择是惰性的。非常懒。事实上,它是如此懒惰,以至于完全忽略了您已经从中看到的任何输出。当你第二次迭代
m_恐龙
时,你会得到一批全新的
恐龙模型
对象


您可以使用
恐龙.ConvertAll(x=>新恐龙视图模型(x))
将模型存储在列表中。

这也是我的第一个想法,但这是错误的。linq将在下一个
foreach
语句中立即计算。无需调用
ToList
,这样做也不会产生任何影响。@PhilipPittle每次迭代
foreach
循环后,都不会保留对新创建的
视图模型的引用,
.ToList()
确保视图模型具体化并保留引用。@PhilipPittle您可以尝试的是一个简单的
var e=new int[]{1,2,3}。选择(i=>{Console.WriteLine(i);返回i;});foreach(vari在e中){/*什么都不做*/}foreach(vari在e中){/*再次什么都不做*/}
。你会看到数字被打印了两次。FWIW,我认为垃圾收集在这里不重要。第一批
对象是否得到GC-ed并不重要:问题只是第二批对象没有任何事件订阅服务器。即使第一批仍然存在,这也是一个问题。@hvd啊,是的,您是正确的,后续的评估将导致不同的视图模型实例,但是我将在这里留下我的答案,因为我以前被延迟的LINQ和GC咬过!这也是我的第一个想法,但那是错误的。linq将在下一个
foreach
语句中立即计算。没有必要打电话