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

本文关键字:函数 成员 指针 实例 对象 | 更新日期: 2023-09-27 18:16:12

我正在尝试用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:需要一个对象引用来访问非静态成员。

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

我花了3天时间寻找解决方案,但是没有。

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

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

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

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

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

我想你想在newev对象上调用函数,对吗?然后你需要更像:

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

我同意你在这里重新发明。net事件/委托的评论。它们一开始看起来确实令人困惑,但随后它们就会出现,你就会明白了。在不编写自己的事件路由代码的情况下尝试解决问题是值得的。

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

的例子:

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);
    }
}