【发布时间】: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
}
}
但它没有工作。我也尝试过找到here和here的解决方案,更改事件声明:
private EventHandler<string> fileReceived;
public event EventHandler<string> OnFileReceived
{
add
{
if (fileReceived == null || !fileReceived.GetInvocationList().Contains(value))
{
fileReceived += value;
}
}
remove
{
fileReceived -= value;
}
}
再次,没有运气。 问题是:我怎样才能防止这种情况发生?
谢谢。
【问题讨论】:
-
Contains将进行参考测试,但value可能是具有相同Target和Method值的不同实例。必须测试这些。 -
您确定只有一个
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<string>(OnFileDownloaded)(在C# 2.0 之前,您必须这样做,使用new)。这与Server.OnFileReceived += OnFileDownloaded;的 instance 不同。在add访问器中,value的实例与您调用fileReceived.GetInvocationList()时在调用列表中找到的实例不同。