【问题标题】:Using delegates with arguments使用带参数的委托
【发布时间】:2010-01-06 11:44:38
【问题描述】:

我有一个类'KeyEvent';其中一个成员是:

public delegate void eventmethod(object[] args);

并且在构造函数中传递给对象的方法存储在这个成员中:

private eventmethod em;

构造函数:

  public KeyEvent(eventmethod D) {
   em = D;
  }
  public KeyEvent(eventmethod D, object[] args) : this(D) {
   this.args = args;
  }
  public KeyEvent(Keys[] keys, eventmethod D, object[] args) : this(keys, D) {
   this.args = args;
  }

然后使用公共方法“ThrowEvent”调用“eventmethod”方法:

  public void ThrowEvent() {
   if (!repeat && thrown) return;
   em.DynamicInvoke(args);
   this.thrown = true;
  }

据我所知,这编译得很好。但是在尝试创建此类(KeyEvent)的实例时,我做错了。这是我目前所拥有的:

   object[] args = {new Vector2(0.0f, -200.0f)};
   Keys[] keys = { Keys.W };
   KeyEvent KeyEvent_W = new KeyEvent(keys, new KeyEvent.eventmethod(GameBase.ChangeSquareSpeed), args);

GameBase.ChangeSquareSpeed 目前没有做任何事情,但看起来像这样:

  static public void ChangeSquareSpeed(Vector2 squarespeed) {

  }

反正错的就是这一行:

KeyEvent KeyEvent_W = new KeyEvent(keys, new KeyEvent.eventmethod(GameBase.ChangeSquareSpeed), args);

编译器给我的错误是:

错误 CS0123:“ChangeSquareSpeed”没有重载匹配委托“BLBGameBase.KeyEvent.eventmethod”

我的问题是:这是否意味着我必须更改 ChangeSquareSpeed 以不使用任何参数(在这种情况下,有什么更好的方法?),还是我在语法上做错了什么?

提前谢谢你。

【问题讨论】:

    标签: c# delegates arguments


    【解决方案1】:

    我认为错误非常明确。您的 ChangeSquareSpeed 方法与委托不匹配。委托需要一个带有 object[] 作为参数的方法,但是您传递了一个带有 Vector2 作为参数的方法,因此会出现错误。

    试试这个方法:

    static public void ChangeSquareSpeed(object[] squarespeed) 
    {}
    

    (更新)

    我在您的代码中看到了一些混乱,特别是在以下行中:

    object[] args = {new Vector2(0.0f, -200.0f)};
    

    我真的不明白你是想要一个 Vector2 的数组还是只是一个 Vector2 的对象。

    如果你假装有一个Vector2 的数组,我认为这似乎是合理的:

    将委托更改为:

    public delegate void eventmethod(Vector2 args);
    

    然后

    public void ThrowEvent() {
       if (!repeat && thrown) return;
       foreach(object obj : args)
       {
          em.DynamicInvoke((Vector2)obj);
       }
       this.thrown = true;
    }
    

    (更新 2)

    在这种情况下,我认为您应该创建一个通用版本的KeyEvent。请参阅此示例并从那里开始:

        class KeyEvent<T>
        {
            public T Args { get; set; }
            public Action<T> A { get; set; }
    
            public KeyEvent() { }
    
            public void ThrowEvent()
            {
                A.DynamicInvoke(Args);
            }
        }
    
        // ...
    
        static void M1(object[] o)
        {
            Console.WriteLine("M1 {0}", o);
        }
    
        static void M2(Vector2 v)
        {
            Console.WriteLine("M2 {0}", v);
        }
    
        static void Main(string[] args)
        {
            KeyEvent<object[]> e1 = new KeyEvent<object[]>
            { 
               A = new Action<object[]>(M1),
               Args = new object[] {};
            };
            KeyEvent<Vector2> e2 = new KeyEvent<Vector2>
            {
               A = new Action<Vector2>(M2),
               Args = new Vector2();
            };
        }
    

    【讨论】:

    • 然而,在这种情况下,我将如何使用传递给 squarespeed 的对象作为向量?我只想在 ChangeSquareSpeed 中使用 Vector2 - 没有更好的方法吗?
    • @Motig,查看我的更新。我真的不知道你是想要一个 Vector2 的数组还是只是一个 Vector2 的对象作为 KeyEvent 的参数。
    • 嗯,这很合适,但我需要委托事件方法灵活。在这种情况下,我使用它来传递 Vector2,但我也可以传递其他任何东西,具体取决于要调用的“事件”到底是什么。
    【解决方案2】:

    委托eventmethod 声明所有使用它的事件都应将object[] (args) 作为其唯一的in 参数。根据您使用此代码的目的,您希望:

    • 将ChangeSquareSpeed的签名改为ChangeSquareSpeed(object[] squarespeed)
    • 使用签名void neweventmethod(Vector2 args); 创建一个新委托并使用它
    • 把eventmethod的签名改成上面的样子

    【讨论】:

      【解决方案3】:

      如果您使用的是 C# 3,请将委托更改为 Action&lt;object[]&gt;。这将使您的生活变得更加简单,因为调用它是类型安全的。

      这将允许您像这样简单地调用它:

      this.em(args);
      

      您将进行编译时检查。

      【讨论】:

      • 使用委托 Action 而不是 Func。 Func 使用第一个泛型作为返回类型;它不是参数类型。操作返回 void,因此列出的所有泛型类型都是参数类型。
      • 这是正确的 - 感谢您指出这一点。更新了答案。
      猜你喜欢
      • 2010-12-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多