c# - 如何创建指向另一个 Action C# 的 Action?

标签 c# pointers delegates action ref

我在 C# 中遇到了一些意外行为。我基本上是在尝试将一个操作分配给另一个操作的引用,以便我可以稍后订阅/取消订阅引用操作的方法。我不想知道实现引用操作的类。

问题是,应该指向我想听的 Action 的 Action 似乎并没有真正指向它。我认为它会在引发引用操作时引发,但显然情况并非如此。

我可能对委托(delegate)有一些误解。有人可以告诉我我做错了什么吗?是否有针对我要实现的目标的解决方案?

感谢任何回复!

public class WaitForActionProcess : IProcess
{
    public Action Finished { get; set; }
    Action actionHandler;

    public WaitForActionProcess(ref Action action)
    {
        actionHandler = action;
    }

    public void Play()
    {
        actionHandler += RaiseFinished;
    }

    public void RaiseFinished()
    {
        actionHandler -= RaiseFinished;

        if(Finished != null)
        {
            Finished();
        }
    }
}

使用示例:

public class ReturnToMainMenuFrame : TutorialEventFrame
{
    [SerializeField]
    TutorialDialogueData dialogueData;

    [SerializeField]
    PointingArrowData arrowData;

    [SerializeField]
    TutorialDialogue tutorialDialogue;

    [SerializeField]
    PointingArrow arrow;

    [SerializeField]
    MainView mainView;

    public override void StartFrame()
    {
        frameProcesses.Add(new ShowPointToUIProcess(arrow, arrowData));
        frameProcesses.Add(new ShowDialogueProcess(tutorialDialogue, dialogueData));
        frameProcesses.Add(new WaitForActionProcess(ref mainView.OnViewShown));
        frameProcesses.Add(new HideDialogueProcess(tutorialDialogue, this));
        frameProcesses.Add(new HidePointToUIProcess(arrow,this));
        base.StartFrame();
    }

}

框架基础实现:

public class TutorialEventFrame : MonoBehaviour {

    public delegate void OnFrameEnded();
    public event OnFrameEnded FrameEnded;

    public List<IProcess> frameProcesses = new List<IProcess>();

    public bool debugMode = false;

    public virtual void StartFrame()
    {
        StartProcess(0);
    }

    void StartProcess(int processIndex)
    {
        if (processIndex < frameProcesses.Count)
        {
            int nextProcessIndex = processIndex + 1;
            frameProcesses[processIndex].Finished += () => StartProcess(nextProcessIndex);
        }
        else
        {
            EndFrame();
            return;
        }

        if (debugMode)
        {
            Debug.Log("Starting process: " + frameProcesses[processIndex] + " of processes: " + (processIndex + 1) + "/" + (frameProcesses.Count - 1) + " on frame: " + name);
        }

        frameProcesses[processIndex].Play();           
    }

    public virtual void EndFrame() {

        foreach (var process in frameProcesses)
        {
            process.Finished = null;
        }

        if (debugMode)
        {
            Debug.Log("frame: " + name + " finished");
        }
        frameProcesses.Clear();

        if (FrameEnded != null) {
            FrameEnded();
        }
    }
}

最佳答案

假设 OnViewShown 是一个事件,并且你想在调用 Play 时开始监听这个事件,然后在事件触发时调用 Finished,下面将允许你这样做:

public class WaitForActionProcess : IProcess
{
    public Action Finished { get; set; }

    Action<Action> Subscribe { get; }
    Action<Action> Unsubscribe { get; }

    public WaitForActionProcess(Action<Action> subscribe, Action<Action> unsubscribe)
    {
        Subscribe = subscribe;
        Unsubscribe = unsubscribe;
    }

    public void Play()
    {
        Subscribe(RaiseFinished);
    }

    public void RaiseFinished()
    {
        Unsubscribe(RaiseFinished);
        Finished?.Invoke();
    }
}

调用方法:

 var wfap = new WaitForActionProcess(
       h => mainView.OnViewShown += h, 
       h => mainView.OnViewShown -= h);

请注意,您希望 100% 确定 OnViewShown 将在播放后触发,否则将永远不会调用 Finished,并且您还会遇到内存泄漏,因为您永远不会取消订阅该事件。

虽然它可能在 Unity 中不可用,但请查找 System.Reactive,它使此类事情形式化并使事件处理更易于管理。

关于c# - 如何创建指向另一个 Action C# 的 Action?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50751996/

相关文章:

c# - 将 BitArray 转换为小字节数组

c# - WPF 的 XAML : Hide ToolTip Popup when blank Tooltip text

algorithm - 合并单链表的两半

ios - 从 UITabbarController 中选择选项卡时如何更新 VC 中的值?

c# - 在 C# 中使用 WebClient 有没有办法在重定向后获取站点的 URL?

c# - 比较数据集值

C - 如何打印二维数组中指针[0][0]的值

c++ - 为什么函数不知道数组大小?

ios - 带有来自 plist 的数据的 objective-c 过滤 TableView

C# 函数委托(delegate)