c#指向没有对象实例的函数成员

时间:2013-05-31 14:15:32

标签: c# events

我试图在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 I中尝试将委托传递给每个侦听器必须执行的方法。

应该看一下示例。像这样:

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:访问非静态成员需要对象引用。

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

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

4 个答案:

答案 0 :(得分:1)

您可以创建一个带有Delegate.Create重载之一的“open delegate” - 目标对象成为委托的参数(您不需要Call辅助函数,只需{{ 1}}。

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

您还遇到了类型安全问题,因为您的所有侦听器都是methodToInvoke(listener, data),但并非所有实现EventInterface的对象都有EventInterface方法。

答案 1 :(得分:0)

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

答案 2 :(得分:0)

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

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

我会回应那些说你在这里重新发明.Net活动/代表的评论。它们一开始看起来确实令人困惑,但随后它们会点击,你就会得到它。在没有编写自己的事件路由代码的情况下,尝试解决问题是值得的。

答案 3 :(得分: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);
    }
}