我遇到了一些需要重构的代码问题。现在它使用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;
}
并且将操作作为参数传递给扩展事件args,但是当我尝试像这样使用它时
_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
答案 0 :(得分:1)
不,你不能这样做,因为它是引发 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
的事实意味着它是一个非阻塞方法...所以在调用它之后立即取消订阅可能并不是一个好主意。
答案 1 :(得分:1)
当我读到它时,这里的关键问题是无法删除处理程序;如果是这样,你需要它来存储委托(在下面的地方,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;
答案 2 :(得分:0)
如果你更愿意避免使用匿名方法,你可以手动完成编译器为你做的工作。也就是说,创建一个闭包类来保存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;