【问题标题】:How to subscribe to an event with certain arguments c#?如何使用某些参数c#订阅事件?
【发布时间】:2014-05-03 23:54:28
【问题描述】:

我有一个枚举prior

我的每个脚本都有 priority 类型的 prior 属性。 (每个脚本都有自己的类)

我有一个数据提供者,它可以每帧发送事件。

我希望脚本只订阅一个事件,该事件的参数优先级等于脚本的参数。

例如,具有moderate 优先级的脚本应该只接收带有moderate 事件参数参数的事件

prior 的成员太多,无法为每个成员创建一个特殊的事件参数类。

不幸的是:

a)我只知道如何订阅某种事件类型。

b)我不能为事件参数创建一个泛型类,因为枚举的元素不是类型

我该怎么做?


项目目前看起来是这样的:

public class TDefault:MonoBehaviour,IDefault
{ 

    public enum prior
    {
        none,
        ...,
        terminal
    };
    prior priority;
    public virtual void apply()//For override by scripts
    {

    }
    void Start()
    {
        //There should be adding a method which calls apply() when event_manager 
        //sends Event with a certain priority
    }
    public TDefault ()
    {
        if(essential==null)
        essential=new TEssential();
    }

}

public class TApplyEventParam : EventArgs 
{
    public TDefault.prior priority;
    public TApplyEventParam(TDefault.prior _priority)
    {
        priority=_priority;
    }
}

    public class event_manager : TDefault
    {
        //This has fixed type
        event EventHandler<TApplyEventParam> handler=new EventHandler<TApplyEventParam>();
        void Update () 
        {
            foreach (prior p in (prior[]) Enum.GetValues(typeof(prior)))
            {
                handler(this,new TApplyEventParam(p));
            }
        }
    }

【问题讨论】:

  • 那么,这些“脚本”有共同的基类吗?你能改变出版商吗?
  • 是的,他们有,我可以更改发布者。
  • 发布代码大纲。我懒得想象这一切。
  • BuiltInClasses&lt;-TDefault&lt;-... 其中... 包括发布者和所有脚本。大纲是什么意思?
  • @user2136963:请编辑您的问题,而不是发布 cmets。

标签: c# .net


【解决方案1】:

如果我理解正确,您正在处理的问题是您希望根据事件有效负载(TApplyEventParam 中的priority 值)有条件地调用您的事件订阅。这是您无法做到的事情,导致您必须像@Henk-Holterman 建议的那样过滤掉事件处理程序中的 unwanted 事件

另一种方法可能是跳过事件的使用并在数据提供者中维护自己的订阅者列表。 根据您在问题中使用的术语(不是代码示例),您可以执行以下操作:

using System;
using System.Collections.Generic;

namespace Example
{
    public enum Prior
    {
        None,
        Moderate,
        Terminal
    };

    public abstract class ScriptBase
    {
        public abstract Prior Prior { get; }

        public abstract void Apply();

        public void Start(DataProvider dataProvider)
        {
            dataProvider.Subscribe(Prior, Apply);
        }

        public void Stop(DataProvider dataProvider)
        {
            dataProvider.Unsubscribe(Prior, Apply);
        }
    }

    public class ScriptHandlingModerateEvents : ScriptBase
    {
        public override Prior Prior
        {
            get { return Example.Prior.Moderate; }
        }

        public override void Apply()
        {
            Console.WriteLine("Handling moderate event by " + GetType().Name);
        }
    }

    public class ScriptHandlingTerminalEvents : ScriptBase
    {
        public override Prior Prior
        {
            get { return Example.Prior.Terminal; }
        }

        public override void Apply()
        {
            Console.WriteLine("Handling terminal event by " + GetType().Name);
        }
    }

    public class DataProvider
    {
        private readonly Dictionary<Prior, List<Action>> _subscribersByPrior;

        public DataProvider()
        {
            _subscribersByPrior = new Dictionary<Prior, List<Action>>();

            foreach (Prior prior in (Prior[])Enum.GetValues(typeof(Prior)))
            {
                _subscribersByPrior.Add(prior, new List<Action>());
            }
        }

        public void Subscribe(Prior prior, Action action)
        {
            _subscribersByPrior[prior].Add(action);
        }

        public void Unsubscribe(Prior prior, Action action)
        {
            _subscribersByPrior[prior].Remove(action);
        }

        public void DoSomethingThatTriggersPriorEvents(int someValue)
        {
            Prior prior = someValue % 2 == 0 ? Prior.Moderate : Prior.Terminal;
            foreach (var subscriber in _subscribersByPrior[prior])
            {
                subscriber();
            }
        }
    }

    public static class Program
    {
        public static void Main()
        {
            DataProvider dataProvider = new DataProvider();

            var scriptHandlingModerateEvents = new ScriptHandlingModerateEvents();
            scriptHandlingModerateEvents.Start(dataProvider);

            var scriptHandlingTerminalEvents = new ScriptHandlingTerminalEvents();
            scriptHandlingTerminalEvents.Start(dataProvider);

            for (int i = 0; i < 10; i++)
            {
                dataProvider.DoSomethingThatTriggersPriorEvents(i);
            }

            scriptHandlingTerminalEvents.Stop(dataProvider);
            scriptHandlingModerateEvents.Stop(dataProvider);

            Console.WriteLine();
        }
    }
}

这样DataProvider 不知道脚本,但如果这不是问题,您可以维护ScriptBase 实例列表并检查Prior 内的属性 DoSomethingThatTriggersPriorEvents 像这样:

public class DataProvider2
{
    private readonly List<ScriptBase> _scripts = new List<ScriptBase>();

    public void Subscribe(ScriptBase script)
    {
        _scripts.Add(script);
    }

    public void Unsubscribe(ScriptBase script)
    {
        _scripts.Remove(script);
    }

    public void DoSomethingThatTriggersPriorEvents(int someValue)
    {
        Prior prior = someValue % 2 == 0 ? Prior.Moderate : Prior.Terminal;
        foreach (var script in _scripts)
        {
            if (script.Prior == prior)
            {
                script.Apply();
            }
        }
    }
}

【讨论】:

  • 很棒的解决方案。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-22
  • 1970-01-01
相关资源
最近更新 更多