当前位置: 代码迷 >> C# >> 求高手帮助!c#多种方法实现事件机制的有关问题
  详细解决方案

求高手帮助!c#多种方法实现事件机制的有关问题

热度:69   发布时间:2016-05-05 04:49:54.0
求高手帮助!c#多种方法实现事件机制的问题
小弟我初学c#,最近用c#实现了一个事件系统,核心功能包括事件注册和事件触发,模型如下:

//----------------------------------------------------------------------------------------------------
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;

class Event
{
struct Method
{
public object obj;
public MethodInfo methodInfo;

public Method(object obj, MethodInfo methodInfo)
{
this.obj = obj;
this.methodInfo = methodInfo;
}
}

private Dictionary<string, Method> _dictEvent = new Dictionary<string, Method>();

public bool register(string eventname, object obj, MethodInfo methodInfo)
{
_dictEvent[eventname] = new Method(obj, methodInfo);
}

public void fire(string eventname, object[] args)
{
Method method = _dictEvent[eventname];
method.methodInfo.Invoke(obj, args);
}
}

经过测试发现,Invoke的效率不高,频繁调用的情况下严重影响性能,请教高手有没有更好的解决办法呢?

后面研究了一下delegate 委托,但是委托必须具体指明委托的函数类型,无法满足上面例子的要求。


------解决思路----------------------

public bool register(string eventname, Action<object[]> method) {
        //////////
}

------解决思路----------------------
这个效率问题感觉跟 Invoke 关系不大
------解决思路----------------------
。。。为啥要这样写,public void onEat(int type, int num) 这个参数个数是固定的?就是其他的方法也是这参数?
如果固定那就
改这个
private static Dictionary<string, Action<int,int>> _dictEvent = new Dictionary<string, Action<int,int>>();
public static bool register(string eventname, Action<int,int> action)




  class Event
        {


            private static Dictionary<string, Action<int, int>> _dictEvent = new Dictionary<string, Action<int, int>>();

            public static bool register(string eventname, Action<int, int> action)
            {
                _dictEvent[eventname] = action;
                return true;
            }

            public static void fire(string eventname, int arg1, int arg2)
            {
                Action<int, int> method = _dictEvent[eventname];
                if (method != null)
                {
                    method(arg1, arg2);
                }
            }
        }

        //----------------------------------------------------------------------------------------------------
        //Avatar.cs
        class Avatar
        {
            public Avatar()
            {
                Event.register("eat", this.onEat);
            }

            public void onEat(int type, int num)
            {
                //...
            }

            public void walk()
            {
                //...

                Event.fire("eat", 1, 100);

                //...
            }
        }


------解决思路----------------------
引用:
Quote: 引用:

。。。为啥要这样写,public void onEat(int type, int num) 这个参数个数是固定的?就是其他的方法也是这参数?
如果固定那就
改这个
private static Dictionary<string, Action<int,int>> _dictEvent = new Dictionary<string, Action<int,int>>();
public static bool register(string eventname, Action<int,int> action)




  class Event
        {


            private static Dictionary<string, Action<int, int>> _dictEvent = new Dictionary<string, Action<int, int>>();

            public static bool register(string eventname, Action<int, int> action)
            {
                _dictEvent[eventname] = action;
                return true;
            }

            public static void fire(string eventname, int arg1, int arg2)
            {
                Action<int, int> method = _dictEvent[eventname];
                if (method != null)
                {
                    method(arg1, arg2);
                }
            }
        }

        //----------------------------------------------------------------------------------------------------
        //Avatar.cs
        class Avatar
        {
            public Avatar()
            {
                Event.register("eat", this.onEat);
            }

            public void onEat(int type, int num)
            {
                //...
            }

            public void walk()
            {
                //...

                Event.fire("eat", 1, 100);

                //...
            }
        }



参数不是固定的哦,可能还会有其他方法,如果用上了Action<int, int>,那只能触发这个类型的方法,再来一个其它参数的方法,比如 Event.register("sleep", this.onSleep); onSleep没有参数,那就会出错。


那你的这种设计还是错的,不应这样子设计 参数至少一个 无参的你可以转null,参数用object state 这样一个对象传进去,然后在方法里面去做拆箱,如果想做拆箱。那就用BinaryReader BinaryWriter 进行参数的字节封装,参数用字节数组传入

我们像下面这样,如果为空那就不要去Reader buffer


 ServerPacketHandlers.Register(1125, AdsorptionInventoryProcess.OnCarbonAdsorptionAction);
ServerPacketHandlers.Register(1127, AdsorptionInventoryProcess.OnCarbonAdsorptionList);
ServerPacketHandlers.Register(1129, AdsorptionInventoryProcess.OnAllCarbonAdsorptionList);


 public static void OnCarbonAdsorptionAction(int connectionID, int reciveID, byte[] buffer)

             var reader = new ParameterReader(buffer);
            var pageIndex = reader.ReadInt();
            var pageSize = reader.ReadInt();


 public static void OnCarbonAdsorptionList(int connectionID, int reciveID, byte[] buffer)

           var reader = new ParameterReader(buffer);
            var pageIndex = reader.ReadInt();
            var pageSize = reader.ReadInt();


 public static void OnAllCarbonAdsorptionList(int connectionID, int reciveID, byte[] buffer)

          var reader = new ParameterReader(buffer);
            var pageIndex = reader.ReadInt();
            var pageSize = reader.ReadInt();


 
------解决思路----------------------
比如说,人家设计一个 ORM 系统,希望当数据被写入数据库时,数据库系统抛出三类(增删改)事件之中的某一个,于是人家就定义了
public class DB
{
    public event EventHandler<AddArgs> AddCompleted;
    public event EventHandler<UpdateArgs> UpdateCompleted;
    public event EventHandler<DeleteArgs> DeleteCompleted;

......
 


人家的三个参数类型,各有不同的业务属性,非常明确。例如 UpdateArgs 中有属性表示“替换之前的对象,替换之后的对象”。人家的 ORM 系统的使用者可以非常直观地使用这三个事件,因为这在 .net 程序员之中是很傻瓜化地、普通的语法知识。

现在,有个从 java 转行的人不喜欢“基本事件机制”,于是非要自己弄来一套“事件系统”来取代这个,没有提高任何开发效率,反而非常抽象、很有些费解,而且还有10倍以上的性能代价。人家何必要用呢?

你可以将依赖倒置(或者说“控制反转”)机制用在某些“背景明确”的系统中。但是要先考虑一下那些“基于微软技术的”编程者在事件机制方面,从编译器人家是不是早在25年前就已经用编译器来解析事件类型了,而不是用你的用户代码来处理。
------解决思路----------------------
这个你可以参考winform里面Control的事件处理方式,使用EventHandlerList,进行Delegate方式的事件管理。这里有例子。

当然也可以自行实现类似的方式,不过强类型和动态化没那么容易兼得。这种事件派发一般是直接注册Delegate,有时候也可以使用表达式编译Delegate,不要使用反射Invoke。
------解决思路----------------------
引用:
Quote: 引用:


public bool register(string eventname, Action<object[]> method) {
        //////////
}


下面是我的完整例子:注册“eat”事件,该事件绑定onEat方法,通过触发"eat"事件调用到 onEat 方法。
新增注册事件不需要修改Event
用委托如何实现呢??
//----------------------------------------------------------------------------------------------------
// Event.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;

class Event
{
private class Method
{
public object obj;
public MethodInfo methodInfo;

public Method(object obj, MethodInfo methodInfo)
{
this.obj = obj;
this.methodInfo = methodInfo;
}
}

private static Dictionary<string, Method> _dictEvent = new Dictionary<string, Method>();

public static bool register(string eventname, object obj, MethodInfo methodInfo)
{
_dictEvent[eventname] = new Method(obj, methodInfo);
return true;
}

public static void fire(string eventname, object[] args)
{
Method method = _dictEvent[eventname];
method.methodInfo.Invoke(method.obj, args);
}
}

//----------------------------------------------------------------------------------------------------
//Avatar.cs
class Avatar
{
public Avatar()
{
Event.register("eat", this, this.GetType().GetMethod("onEat"));
}

public void onEat(int type, int num)
{
//...
}

public void walk()
{
//...

Event.fire("eat", new object[]{1, 100});

//...
}
}


MethodInfo 属于反射调用了, 效率肯定上不去,
需采用 delegate , interface 都可以 (自带的 泛型 delegate (Func<T>, Action<T>) 就很好)
如果照你所说的 参数个数不确定 无法用 delegate, 那只能是设计得太差劲.
------解决思路----------------------
参数个数不确定
可以使用params关键字
用了反射,也不代表里面没有再使用委托
  相关解决方案