C# 将委托转换为System.Action 介绍

C# 将委托转换为System.Action 介绍,c#,windows-phone-8,event-handling,C#,Windows Phone 8,Event Handling,在我的wp8c#/XAML项目中,我使用事件通知我的视图某些异步过程已经完成 我有两类代表 我正在从这些代理创建事件,其中有几个代理通知我的视图某些操作已完成或启动(为了显示progressbar、导航到另一个页面、禁用某些控件等等) 为了引发这些事件,我想创建一个私有的“通知方法”,它将引发这些委托 我想到的方法在下面的代码示例中是fireUpEvent方法 代码示例 返回状态枚举 public enum ReturnState : int { state1 = 0, ...

在我的wp8c#/XAML项目中,我使用事件通知我的视图某些异步过程已经完成

我有两类代表

我正在从这些代理创建事件,其中有几个代理通知我的视图某些操作已完成或启动(为了显示progressbar、导航到另一个页面、禁用某些控件等等)

为了引发这些事件,我想创建一个私有的“通知方法”,它将引发这些委托

我想到的方法在下面的代码示例中是fireUpEvent方法

代码示例 返回状态枚举

public enum ReturnState : int
{
  state1 = 0,
  ...            //for the purpose of the presentation
  state6 = 15
  ...
}
事件和方法的定义

public delegate void LoadingStartedEventHandler();
public delegate void LoadingFinishedEventHandler(ReturnState state);

public event LoadingStartedEventHandler LoadingStarted;
public event LoadingFinishedEventHandler LoadingFinished;

private void fireUpEvent(Action<ReturnState> action, Returnstate parameter)
{
  if(action != null)
  {
    action(parameter);
  }
}

private void fireUpEvent(Action action)
{
  if(action != null)
  {
    action();
  }
}
描述 问题是,当我尝试编译时,会出现一个错误,错误是:

Argument1:无法从'XXXX.yyy.SomeClass.LoadingFinishedEventHandler'转换为'System.Action'

我试过谷歌搜索,但没有找到任何有用的东西

为什么不能兑换?

我想在这些方法中而不是在特定的代表中执行
操作
操作
,有可能吗?

我是否应该使用任何其他“类型”,如
操作

我从这个“群组”中只知道两个是
Func
Action
,还有其他的吗?

回答这一行:

为什么它不能兑换

它们是不同的委托类型,不同委托类型之间不存在引用转换(使用泛型差异的泛型委托类型除外)。您可以从
LoadingStartedEventHandler
创建
操作,如下所示:

LoadingStartedEventHandler handler = ...; // Whatever
Action action = new Action(handler);
。。。你也可以反过来做同样的事情,用你的其他委托类型和
动作
。但真的没有必要这么做

我想在这些方法中使用
操作
操作
,而不是特定的委托,是否可能

是的-只是不要使用这些委托声明事件,实际上根本不要声明委托

您可以更改此设置:

public delegate void LoadingStartedEventHandler();
public delegate void LoadingFinishedEventHandler(ReturnState state);

public event LoadingStartedEventHandler LoadingStarted;
public event LoadingFinishedEventHandler LoadingFinished;
为此:

public event Action LoadingStarted;
public event Action<ReturnState> LoadingFinished;
并将助手方法更改为:

private void RaiseEvent(EventHandler<TEventArgs> handler,
                        TEventArgs parameter)
{
  if(handler != null)
  {
    handler(this, parameter);
  }
}

private void RaiseEvent(EventHandler handler)
{
  if(handler != null)
  {
    handler(this, EventArgs.Empty);
  }
}
private void RaiseEvent(事件处理程序,
TEventArgs参数)
{
if(处理程序!=null)
{
handler(这个参数);
}
}
私有void RaiseEvent(事件处理程序)
{
if(处理程序!=null)
{
处理程序(此,EventArgs.Empty);
}
}

(我修改了方法名称,使之符合.NET约定,并使用.NET术语来表示事件,这些事件是“引发的”,而不是“激发的”。

斯基特先生总是能给出很好的答案。在这里,我提供了你在问题中所说的另一个解决方案

对于这两位:

  • 为什么它不能兑换
  • 我想在这些方法中采取行动,而不是具体的代表,这可能吗
  • 斯基特先生已经回答了

    对于这两位:

  • 我应该使用其他类型的动作来代替吗
  • 从这个“grooup”中我只知道两个是Func&Action,还有其他的吗
  • 您的
    fireUpEvent
    方法可能不应接受任意类型的委托作为脆弱的设计。但这是可能的

    C#中所有委托类型的最终基类型是
    delegate
    Delegate
    的一个限制是它不能是泛型类型和方法中的
    where
    约束

    要回答这个问题(无论设计如何),您可以说:

    private void fireUpEvent(
            Delegate loadingEvent, ReturnState? parameter=null) {
        if(null!=loadingEvent) {
            foreach(var d in loadingEvent.GetInvocationList()) {
                var args=null!=parameter?new object[] { parameter }:null;
                d.Method.Invoke(d.Target, args);
            }
        }
    }
    
    如果是静态方法,
    Target
    是拥有该方法的对象,则将其视为
    this
    null
    ,而不是问题中最初的两个方法
    args
    是传递给方法的参数列表


    这只是一种实现它的方法,我敢肯定斯基特先生的答案绝对是更好的

    这确实是一个很好的答案,提醒大家注意这些惯例。我不知道。有时候很难找到一个完整的答案来解释原因。很多教程只是以“像这样做,我就是这样做的”的方式展示内容,而没有进一步解释为什么要这样做。这就是为什么你的答案是宝石。谢谢,谢谢你的意见。我已经修改了我的代码以使用EventHandler和我的EventArgs派生版本,这最终比我拥有的第一个解决方案短。我只是从来没有学到很多关于事件的知识,以及如何正确地使用它,这就是为什么我首先问这个问题的原因。我很高兴了解更多+1.
    private void RaiseEvent(EventHandler<TEventArgs> handler,
                            TEventArgs parameter)
    {
      if(handler != null)
      {
        handler(this, parameter);
      }
    }
    
    private void RaiseEvent(EventHandler handler)
    {
      if(handler != null)
      {
        handler(this, EventArgs.Empty);
      }
    }
    
    private void fireUpEvent(
            Delegate loadingEvent, ReturnState? parameter=null) {
        if(null!=loadingEvent) {
            foreach(var d in loadingEvent.GetInvocationList()) {
                var args=null!=parameter?new object[] { parameter }:null;
                d.Method.Invoke(d.Target, args);
            }
        }
    }