向事件处理程序参数添加操作c#

时间:2011-09-09 07:25:18

标签: c# inheritance event-handling

我遇到了一些需要重构的代码问题。现在它使用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

3 个答案:

答案 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;