我创建了一个事件处理程序,它只返回一个对象列表,当调用完成时,我从 Web 服务接收到这些对象。
现在我继续在 Debug模式下运行该应用程序,发现第一次调用该事件时它运行良好,但在它完成后立即第二次触发该事件。我已经检查过并且绝对确定我不会在接收器类中多次调用该事件。
这是我第一次尝试在我的应用程序中创建自定义事件处理程序,因此我不能完全确定实现是否 100% 准确。
有什么可能导致这种情况的想法吗?我创建事件处理程序的方式是否准确?
这是 DataHelper 类
public class DataHelper
{
public delegate void DataCalledEventHandler(object sender, List<DataItem> dateItemList);
public event DataCalledEventHandler DataCalled;
public DataHelper()
{
}
public void CallData()
{
List<DataItem> dataItems = new List<DataItem>();
//SOME CODE THAT RETURNS DATA
DataCalled(this, dataItems);
}
}
这是我订阅事件的地方:
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
GetNewDataItems();
}
private void GetNewDataItems()
{
try
{
DataHelper dataHelper = new DataHelper();
dataHelper.CallData();
dataHelper.DataCalled += new DataHelper.DataCalledEventHandler(dataHelper_DataCalled);
}
catch
{
//Handle any errors
}
}
}
void dataHelper_DataCalled(object sender, List<DataItem> dataItemsList)
{
//Do something with results
//NOTE: THIS IS WHERE THE EXCEPTION OCCURS WHEN EVENT IS FIRED FOR SECOND TIME
}
最佳答案
可能你添加了两次委托(delegate),这可能吗?
在这种情况下,问题不在于谁调用委托(delegate),而在于谁将委托(delegate)添加到事件中。
可能你做了类似...
private Class1 instance1;
void callback(...)
{
}
void myfunction()
{
this.instance1.DataCalled += this.callback;
this.instance1.DataCalled += this.callback;
}
如果没有,尝试在你订阅事件的地方加个断点,看看它是否被调用了两次。
作为旁注,您应该在调用事件时始终检查是否为 null,如果没有订阅者,您可以获得 NullReferenceException。 我还建议您使用变量来存储事件委托(delegate),以避免多线程失败的风险。
public void CallData()
{
List<DataItem> dataItems = new List<DataItem>();
var handler = this.DataCalled;
if (handler != null)
handler(this, dataItems);
}
编辑:因为现在我看到了代码,很明显,每次您调用 GetNewDataItems 方法时,您每次都会订阅该事件。 以这样的方式您只订阅一次,例如,在构造函数中,或将您的变量存储在某处或在您完成后注销事件。
此代码还包含一个可能的内存泄漏:每次添加委托(delegate)时,都会使包含事件的实例和包含订阅方法的实例保持事件状态,至少,直到两者都未被引用。
你可以尝试做这样的事情......
void dataHelper_DataCalled(object sender, List<DataItem> dataItemsList)
{
// Deregister the event...
(sender as Class1).DataCalled -= dataHelper_DataCalled;
//Do something with results
}
然而,通过这种方式,您必须确保如果在事件注册期间没有异常,事件将被触发,否则您将再次发生内存泄漏。
也许您只需要一个委托(delegate)而不是一个事件。当然,当你想释放委托(delegate)时,你应该将你的委托(delegate)字段设置为 null。
// in data helper class
private DataHelper.DataCalledEventHandler myFunctor;
public void CallData(DataHelper.DataCalledEventHandler functor)
{
this.myFunctor = functor;
//SOME CODE THAT RETURNS DATA
}
// when the call completes, asynchronously...
private void WhenTheCallCompletes()
{
var functor = this.myFunctor;
if (functor != null)
{
this.myFunctor = null;
List<DataItem> dataItems = new List<DataItem>();
functor(this, dataItems);
}
}
// in your function
... dataHelper.CallData(this.dataHelper_DataCalled); ...
关于c# - 自定义事件处理程序被调用两次?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8020940/