我试图在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天,但没有。
答案 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);
}
}