为什么异步对Elapsed事件不起作用?

时间:2015-06-05 21:47:31

标签: c# asynchronous void

嗨我想从一个函数中调用一个子程序,但似乎不可能:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Timers; 
using UnityEngine;
public class StickTimerBetaCoroutine2 : MonoBehaviour
{
        public static float energy = 50.0f;
        private static float pastEnergy = energy;
        public void Update ()
        {
                System.Timers.Timer energyTimer = new System.Timers.Timer ();
                energyTimer.Elapsed += new ElapsedEventHandler (onEnergyTimer);
                energyTimer.Interval = 3000;
                energyTimer.Enabled = true;
                {
                        if (JoeysInputStick.flex <= 0) {
                                energy -= 8 * (Time.deltaTime);
                        } else if (JoeysInputStick.flex >= 1) {
                                energy += 2;
                        } else if (JoeysInputStick.flex >= 2) {
                                energy += 5;
                        } else if (JoeysInputStick.flex >= 3) {
                                energy += 7;
                        } else if (JoeysInputStick.flex >= 4) {
                                energy += 9;
                        } else if (JoeysInputStick.flex >= 5) {
                                energy += 11;
                        } else if (JoeysInputStick.flex >= 6) {
                                energy += 13;
                        }
                }
                energy = Mathf.Clamp (energy, 0.0F, 600.0F); 
                RectTransform rTrans = (RectTransform)transform.GetComponent<RectTransform> ();
                rTrans.sizeDelta = new Vector2 (200, energy);   
        }   
        private async void onEnergyTimer (object source, ElapsedEventArgs e)
        {
                if (energy < pastEnergy - 20) {
                        JoeysInputStick.SendTensOn ();
                        await Task.Delay (800);
                        JoeysInputStick.SendTensOff ();
                }
                pastEnergy = energy;
        }
}

作为一种解决方法,我试过这个但是当我尝试下面的代码时,我得到错误“类,结构或接口成员声明中的意外符号无效”

{{1}}

3 个答案:

答案 0 :(得分:1)

删除异步关键字

您不应该在该功能上使用async关键字。 Elapsed计时器事件不是在寻找异步方法。

您希望直接引用预先存在的private static void onEnergyTimer。我假设您使用反编译器(ilspy或其他)获得了该代码段,并且无法更改该代码。

为什么异步不能处理事件处理程序

事件处理程序通常不支持/期望调用异步方法。我不确定,但我认为您正在使用的那个使用Windows消息泵对消息进行排队以对Elapsed信号进行操作。 Windows Message泵就在那里,所有UI交互都发生在拥有控制句柄的主线程上。

异步模式不适用于计时器。相反,如果你确实想要一个异步等效的延迟,你会改为将Update函数标记为Async,然后不使用Timer和Elapsed函数,而是添加以下行:

            await Task.Delay(3000); //Here's your delay
            if (energy < pastEnergy - 20) {
                    JoeysInputStick.SendTensOn ();
                    await Task.Delay (800);
                    JoeysInputStick.SendTensOff ();
            }
            pastEnergy = energy;

将第三方onEnergyTimer功能标记为公开

您可以编辑第三方DLL(可能),而不是实现您自己的可访问onEnergyTimer函数,将函数更改为public。有很多方法可以做到这一点,一个是请求第三方更新它们对该功能的可访问性,另一个技术解决方案是使用Mono Cecil库(如果需要,我可以进入更多细节,只需发表评论) - 如果您可以控制已升级的DLL,并且您确实希望它们的该版本的功能保持一致,那么这将最有效。

答案 1 :(得分:0)

您尝试将方法签名放在任何类之外,编译器希望您声明类,结构或接口。将您的方法移到课堂内。

public class MyClass
{
    ...

    private async void onEnergyTimer(object source, ElapsedEventArgs e)
    {
        if (energy < pastEnergy - 20) {
            JoeysInputStick.SendTensOn();
            await Task.Delay(800);
            JoeysInputStick.SendTensOff();
        }
        pastEnergy = energy;
    }
}

这种错误经常发生,因为你的花括号没有正确匹配。如果您认为您的方法是在您的课程中声明的,请检查您的大括号,看看您是否有一个你不想要的右括号}

答案 2 :(得分:0)

我得到了一些帮助,结果发现这个问题是由编辑器(mono develop)和Unity(游戏引擎)使用的.net版本引起的。我无法更改这些因素中的任何一个因此我们使用下面的代码作为解决方法:

private Queue energyQueue = new Queue();
        private bool tensInAction = false;
        private void onEnergyTimer (object source, ElapsedEventArgs e)
        {
            float maxEnergy = 0;
            foreach (System.Object reading in (IEnumerable) energyQueue) {
                if ((float) reading > maxEnergy) {
                    maxEnergy = (float) reading;
                }
            }

            if (energy < maxEnergy - 20 && !tensInAction) {
                energyQueue.Clear();
                tensInAction = true;
                JoeysInputStick.SendTensOn ();
                System.Timers.Timer tensTimer = new System.Timers.Timer ();
                tensTimer.Elapsed += new ElapsedEventHandler (onTensTimer);
                tensTimer.Interval = 800;
                tensTimer.Enabled = true;
            }

            energyQueue.Enqueue(energy);
            if (energyQueue.Count > 12) {
                energyQueue.Dequeue();
            }

        }

    private void onTensTimer (object source, ElapsedEventArgs e) {
            JoeysInputStick.SendTensOff ();
            tensInAction = false;
        }