【问题标题】:c# event invoked twicec#事件被调用两次
【发布时间】:2022-01-19 18:52:36
【问题描述】:

我有一个接收文件的服务器。收到文件后,将调用一个事件。 它的工作原理是这样的:

public void Receive() {
    // do some file receiving 
    // decrypt received file
    // save file

    // when file is received decrypted and saved, invoke event:   
    OnFileReceived?.Invoke(this, fileName);

}

...

public static event EventHandler<string>? OnFileReceived;


我在其他类的构造函数中订阅了这个事件,所以它会启动一个打开文件资源管理器的方法。该类只有一个实例,所以我很确定该事件应该只调用一次。

public Foo {
   // constructing object
   // subscribing to events:
   Server.OnFileReceived -= OnFileDownloaded;
   Server.OnFileReceived += OnFileDownloaded;
}

...

 private void OnFileDownloaded(object? sender, string filename)
        {
            InfoLabel = "Received: " + filename;
            OpenDirectory();
        }

问题是文件资源管理器打开了两次。我做了一些调查,结果发现由于某种原因我的事件在 Receive() 方法中被调用了两次。它让我发疯。

我首先尝试通过向 OnFileDownloaded 方法添加一个简单的布尔值来解决这个问题:

private void OnFileDownloaded(object? sender, string filename)
        {
            if (!_isInvoked)
            {
                _isInvoked = true;
                InfoLabel = "Received: " + filename;
                OpenDirectory(); // then setting here _isInvoked back to false after closing the File explorer
            }
        }

但它没有工作。我也尝试过找到herehere的解决方案,更改事件声明:

private EventHandler<string> fileReceived;
public event EventHandler<string> OnFileReceived
{
    add
    {
        if (fileReceived == null || !fileReceived.GetInvocationList().Contains(value))
        {
            fileReceived += value;
        }
    }
    remove
    {
        fileReceived -= value;
    }
}

再次,没有运气。 问题是:我怎样才能防止这种情况发生?

谢谢。

【问题讨论】:

  • Contains 将进行参考测试,但value 可能是具有相同TargetMethod 值的不同实例。必须测试这些。
  • 您确定只有一个 Foo 实例吗?如果是这样,您为什么需要Server.OnFileReceived -= OnFileDownloaded;?如果有多个实例,则该代码将无法工作,因为它引用了不同实例的方法。我建议你在Foo的构造函数中设置一个断点,看看它被击中了多少次。如果将OnFileDownloaded 设为static 函数会怎样?
  • @Charlieface 我确定因为 Foo 是一个 ViewModel,每个 View 只能有一个 ViewModel 实例。我将Server.OnFileReceived -= OnFileDownloaded; 放在 Foo 的构造函数中,因为我在有问题的链接中发现了这样的建议 - 但无论有没有它,它都不起作用。我也无法将OnFileDownloaded 设为静态,因为其中包含一些非静态方法,这些方法也无法设为静态。
  • @madreflection 我不确定我是否理解。如果 Foo 类只有一个且只有一个实例,那么值怎么可能是不同的实例?
  • 不是“a”值,而是add 访问器中value 参数的 值。当您执行Server.OnFileReceived -= OnFileDownloaded; 时,右侧的OnFileDownloaded 实际上是new EventHandler&lt;string&gt;(OnFileDownloaded)(在C# 2.0 之前,您必须这样做,使用new)。这与 Server.OnFileReceived += OnFileDownloaded;instance 不同。在add 访问器中,value 的实例与您调用fileReceived.GetInvocationList() 时在调用列表中找到的实例不同。

标签: c# events


【解决方案1】:

正如 cmets 中的先生所建议的那样,我的问题是由两次调用 Foo 的构造函数引起的,然后导致了 Foo 的两个单独的对象。而且由于该事件是在上述构造函数中订阅的……我又多了一个订阅者。

我很确定这不可能,因为我在代码中搜索了另一个调用 Foo 的构造函数:new Foo(),结果发现什么都没有。我的致命错误是假设我与调用构造函数的方式一致......

然后在代码深处的某个地方我发现了这条孤独的线:

private Foo? _viewModel = new();

过多的糖会让你的牙齿变坏,过多的语法糖会让你发疯。经验教训:连贯一致

【讨论】:

猜你喜欢
  • 2011-10-05
  • 2011-07-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-05
  • 1970-01-01
  • 2017-03-15
  • 1970-01-01
相关资源
最近更新 更多