0

我正在尝试在 C# 中开发事件模型。我是 C# 的新手,有 C++ 经验。我的问题是:我可以在没有类实例的情况下创建一个方法的委托吗?看看这段代码:

public delegate void _CurrentDelegate<EventData>( EventData ev );


public class EventInterface{

    public void Call<EventData>( _CurrentDelegate<EventData> methodToInvoke, EventData data ){
        methodToInvoke( data );
    }
}

public class EventClass {

    protected List<EventInterface> _Listeners;

    private bool _InBlock;

    public EventClass(){
        _Listeners = new List<EventInterface>();
        _InBlock = false;
    }

    public void AddListener( EventInterface listener ){

        if ( _Listeners.Find( predicate => predicate.Equals(listener) ) != null )
            return;

        _Listeners.Add( listener );

    }

    public void RemoveListener( EventInterface listener ){
        if ( _Listeners.Find( predicate => predicate.Equals(listener) ) != null )
            _Listeners.Remove( listener );
    }

    public void BlockEvents( bool Block ){
        _InBlock = Block;
    }


    public void Signal<EventData>( _CurrentDelegate<EventData> methodToInvoke, EventData data ){
        if ( !_InBlock ){
            foreach( EventInterface listener in _Listeners ){
                listener.Call( methodToInvoke, data );
            }
        }
    }

}

所以,我正在尝试创建一个模板事件类,我可以在其中存储我的监听器。在方法 Signal 中,我试图将委托传递给每个侦听器都必须执行的方法。

例子应该看。像这样:

public class TableManagerEvents : EventInterface {

    virtual public void OnMatchDetected( List<int> matches ) {}
}

public class TableManager : AstronomatchData.EventClass {
     public void CheckTable(){
        List<int> matches = new List<int>();
        TableManagerEvents newev = new TableManagerEvents();

        AddListener( newev );

        _CurrentDelegate<List<int>> del = TableManagerEvents.OnMatchDetected; // problem
        Signal( del, matches ); 
    }

}

标记为问题的那一行,我收到一个错误错误 CS0120: An object reference is required to access non-static member。

我找到的一个解决方案是制作一个TableManagerEvents.OnMatchDetected静态的,但这不是我想要的。

我试图找到一个解决方案 3 天,但没有。

4

4 回答 4

1

您可以使用其中一个重载创建“开放委托” Delegate.Create——目标对象成为委托的参数(您不需要Call辅助函数,只需methodToInvoke(listener, data).

然而,正如 Uatec 所说,在支持 lambda 的 C# 版本中,它们比开放委托更容易使用。(主要是因为 C# 语言不直接支持开放委托,而是强制您使用反射来创建它们。)

您还有一个类型安全问题,因为您的所有侦听器都是EventInterface,但并非所有实现的对象EventInterface都有OnMatchDetected方法。

于 2013-06-01T00:56:08.850 回答
0

不在事件类中注册侦听器而是使用某种路由器不是更容易吗?

例子:

public class Event
{

}

public abstract class EventHandler
{
    public abstract void Handle(Event e);
}

public class EventHandler<T> : EventHandler where T : Event
{
    private readonly Action<T> _action;

    public EventHandler(Action<T> action)
    {
        _action = action;
    }

    public override void Handle(Event e)
    {
        _action((T) e);
    }
}

public static class EventRouter
{
    private static readonly Dictionary<Type, List<EventHandler>> Handlers = new Dictionary<Type, List<EventHandler>>();

    public static void Register<T>(Action<T> handler) where T : Event
    {
        List<EventHandler> list = null;

        if(Handlers.TryGetValue(typeof(T), out list))
        {
            list.Add(new EventHandler<T>(handler));
            return;
        }

        Handlers[typeof(T)] = new List<EventHandler>() { new EventHandler<T>(handler)};
    }

    public static void Signal(Event e)
    {
        List<EventHandler> list = null;

        if(Handlers.TryGetValue(e.GetType(), out list))
        {
            list.ForEach(h => h.Handle(e));
        }
    }

    public static void Signal<T>(Action<T> init) where T : Event, new()
    {
        var e = new T();
        init(e);

        Signal(e);
    }
}
于 2013-06-01T01:07:57.993 回答
0

尝试使用 Lambda 表达式 ( http://msdn.microsoft.com/en-us/library/vstudio/bb397687.aspx ) 来表示您的回调而不是委托对象。您可以像变量一样在任何地方创建它们,像函数指针一样传递它们,并像方法/函数一样执行它们。它们也是一种委托,因此也与所有这些兼容。

于 2013-05-31T14:22:02.440 回答
0

我想你想在newev对象上调用函数,对吧?然后你需要更多类似的东西:

_CurrentDelegate<List<int>> del = newev.OnMatchDetected;

我将回应那些说您正在重新发明 .Net 事件/代表的评论。起初它们看起来确实令人困惑,但随后它们会点击,您就会明白。在不编写自己的事件路由代码的情况下尝试解决问题是值得的。

于 2013-06-01T00:44:45.097 回答