为事件处理程序参数添加动作
本文关键字:添加 参数 事件处理 程序 | 更新日期: 2023-09-27 18:08:18
我有一些需要重构的代码问题。现在它使用lambdas作为事件处理程序,但它们没有被正确删除。据我所知,这根本不可能?无论如何,我想重写它,使用一个委托,而不是一个匿名函数,现在我的问题是,现在它把一个动作作为参数,我似乎不知道如何把动作传递给我的新委托。这是代码:
void RetrieveData(
int pointId,
int? chartCollectionId,
Action action)
{
if (pointId <= 0)
throw new ArgumentException("PointId not valid");
LastPointId = NextPointId;
NextPointId = pointId;
Clear();
_csr = new CustomerServiceRepository();
_csr.ServiceClient.GetChartDataCompleted += (se, ea) =>
{
_cachedCharts = ea.Result;
ChartDataRetrieved(ea.Result);
if (action != null)
action.Invoke();
_csr = null;
};
_csr.ServiceClient.GetChartDataAsync(
Settings.Current.Customer.CustomerName,
pointId,
chartCollectionId);
_csr.ServiceClient.GetChartDataCompleted -= (se, ea) => //remove after usage
{
_cachedCharts = ea.Result;
ChartDataRetrieved(ea.Result);
if (action != null)
action.Invoke();
_csr = null;
};
}
我想也许我可以创建以下内容:
public class extendedEventArgs : GetChartDataCompletedEventArgs
{
Action foo { get; set; }
}
void tang(object sender, extendedEventArgs e)
{
_cachedCharts = e.Result;
ChartDataRetrieved(e.Result);
if (action != null)
action.Invoke();
_csr = null;
}
传递动作作为扩展事件参数的参数,但当我尝试像这样使用它
_csr.ServiceClient.GetChartDataCompleted += new EventHandler<extendedEventHandler>(tang);
给出错误:
Cannot implicitly convert type System.EventHandler<Conwx.Net.Client.CustomerClient.Controls.ChartControls.ChartListForecast.extendedEventArgs>' to System.EventHandler<Conwx.Net.Client.Framework.CustomerServiceReference.GetChartDataCompletedEventArgs>'
我在这里做错了什么?也欢迎其他解决方案。
。K
当我阅读它时,这里的关键问题是无法删除处理程序;如果是这样,您需要它来存储委托(在下面,YourDelegateType
意味着:GetChartDataCompleted
的定义类型):
YourDelegateType handler = (se, ea) =>
{
_cachedCharts = ea.Result;
ChartDataRetrieved(ea.Result);
if (action != null)
action.Invoke();
_csr = null;
};
_csr.ServiceClient.GetChartDataCompleted += handler;
...
_csr.ServiceClient.GetChartDataCompleted -= handler;
你也可以使它自取消订阅(即,当事件引发时它取消订阅):
YourDelegateType handler = null;
handler = (se, ea) =>
{
_cachedCharts = ea.Result;
ChartDataRetrieved(ea.Result);
if (action != null)
action.Invoke();
_csr.ServiceClient.GetChartDataCompleted -= handler;
_csr = null;
};
_csr.ServiceClient.GetChartDataCompleted += handler;
不,你不能这样做,因为它的类引发 GetChartDataCompleted
事件,创建对象传递(作为引用)给事件处理程序。它将创建一个GetChartDataCompletedEventArgs
,而不是extendedEventArgs
。
如果你想一下,它就像试图实现一个接口,看起来像这样:
public interface IFoo
{
void Foo(object x);
}
和这样的类:
public class Bar : IFoo
{
// We don't care if someone calling IFoo wants to pass us something
// other than a string - we want a string, darn it!
public void Foo(string y)
{
Console.WriteLine(y.Length);
}
}
这显然是行不通的…
Marc已经展示了一种修复它的方法——但我也要指出,你应该实际上只在事件触发时删除委托。我假设该方法被称为GetChartDataAsync
意味着它是一个非阻塞方法…因此,在调用事件后立即取消订阅可能不是一个好主意。
如果您希望避免使用匿名方法,您可以手动完成编译器在底层为您完成的工作。也就是说,创建一个闭包类来保存Action和对自身的引用作为字段,并公开您想要分配给事件的方法。像这样:
class RetrieveDataClosure
{
private Action action;
private MyClass self;
public RetrieveDataClosure(Action action, MyClass self)
{
this.action = action;
this.self = self;
}
public void ChartDataCompleted(object se, MyEventArgs ea)
{
self._cachedCharts = ea.Result;
self.ChartDataRetrieved(ea.Result);
if (action != null)
action.Invoke();
self._csr = null;
}
}
你可以在你的代码中这样使用:
var closure = new RetrieveDataClosure(action, this);
_csr = new CustomerServiceRepository();
_csr.ServiceClient.GetChartDataCompleted += closure.ChartDataCompleted;
_csr.ServiceClient.GetChartDataAsync(
Settings.Current.Customer.CustomerName,
pointId,
chartCollectionId);
_csr.ServiceClient.GetChartDataCompleted -= closure.ChartDataCompleted;