2011-09-09 78 views
0

我有一些需要重构的代码有问题。现在它使用lambda作为事件处理程序,但它们不能正确删除。从我读过的内容来看,这甚至不可能?无论如何,我想重写它使用委托,而不是一个匿名函数,现在我的问题是,现在它需要一个行动作为参数,我似乎无法弄清楚如何将行动传递给我的新代表。这是代码:向事件处理程序参数添加一个动作c#

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

回答

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; 
+0

这看起来很有希望,非常感谢! – Keller

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这一事实意味着它是一种非阻塞方法......因此在调用它之后立即退出事件可能不是一个好主意。

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; 
+0

尽管如果我是你,我会和Marc的自我取消回答一起去...... – gzak