我正在尝试创建一个简单的事件管理器,但我正在努力按照我想要的方式创建它。
这是我到目前为止所做的,并且它有效。但是,我无法弄清楚如何允许不同的参数并且它们是可选的。
public void some_method(){
// Do something when an enemy has been killed;
}
Event_Manager.on("enemy_killed", some_method);
Event_Manager.trigger("enemy_killed");
使用它的例子:
public void player_damaged(int damage){
// Reduce health
}
Event_Manager.on("player_hit", player_damaged);
Event_Manager.trigger("player_hit", 15);
我希望能够做的是传递不同类型的参数(或某种对象,可能是方法接收的事件)。
(\d+-(?:WARN|PREVENT).*?)(?=,\d+-(?:WARN|PREVENT)|,$)
非常感谢任何帮助。
由于
答案 0 :(得分:1)
您肯定注意到委托类型Action
没有参数。记住这一点。
一种解决方案是使用额外参数传递对象。这方面的细节是您不知道所需参数的类型甚至数量。
在.NET中,这可以通过EventArgs
和每个需要的新事件来解决
创建派生类型的额外参数的不同组合。
这意味着您可以像以下一样使用它:
Event_Manager.trigger("player_hit", new PlayerHitEventArgs(15));
PlayerHitEventArgs
是继承自EventArgs
的类,而trigger
方法需要EventArgs
。同样,您将使用Action<EventArgs>
(在参数和内部字典中)。
我得到的,你想避免麻烦。
下一个选项是始终传递object
,然后接收方必须检查类型并尝试投射它。或者更好的是,通过dynamic
。
在这种情况下,您将使用Action<dynamic>
,触发器方法将使用dynamic
,现在您可以传递匿名类型:
public void player_damaged(dynamic data){
var damage = data.damage;
// Reduce health
}
Event_Manager.on("player_hit", player_damaged);
Event_Manager.trigger("player_hit", new {damage = 15});
注意:也相应地更改字典的类型。
如果您希望代码能够检测act
方法具有多少参数,并尝试相应地传递参数,则需要进行一些反思。
首先,您必须放宽从Action
到Delegate
的类型,因为您将传递带有所有参数的内容。
然后,为了调用,首先需要读取当前委托具有的参数。为此,您必须获得代理人的MethodInfo
:
MethodInfo methodInfo = item.Method;
并且您还需要委托的目标对象,因为它可能不是静态方法:
object target = item.Target;
现在,我们可以阅读参数列表frm MethodInfo
:
var paramList = method.GetParameters();
我们必须构建一个数组来调用方法,我们从列表中获取的大小:
var args = new object[paramList.Length];
然后开始使用对象中的值填充它。这里没有必要使用动态。
触发代码:
public static void trigger(string evt, object obj){
Delegate item;
if(event_list.TryGetValue(evt, out item)){
// Get MethodInfo and Target
MethodInfo methodInfo = item.Method;
object target = item.Target;
// Get the parameter list
var paramList = methodInfo.GetParameters();
// Get the type of the obj
var type = obj.GetType();
// Build the argument list
var args = new object[paramList.Length];
for (int index = 0; index < paramList.Length; index++)
{
var parameter = paramList[index];
var name = parameter.Name;
// Get the value from obj
var property = type.GetProperty(name);
var value = property.GetValue(obj, null);
args[index] = value;
}
// Invoke
methodInfo.Invoke(target, args);
}
}
注意:没有异常处理。还要记住要打开包含代表的字典。
使用示例:
public void player_damaged(int damage){
// Reduce health
}
Event_Manager.on("player_hit", new Action<int>(player_damaged));
Event_Manager.trigger("player_hit", new {damage = 15});
damage
中传递的属性trigger
按名称映射到damage
中的参数player_damage
。我测试了这个作品。
注意:由于on将采用Delegate
,编译器无法为&#34;方法组&#34;选择委托类型,因此需要转换为委托类型。
答案 1 :(得分:1)
然后您需要将字典更改为
Dictionary<string, Action<object>>
和触发方法就像
public static void trigger(string evt, object parameter){
Action<object> item;
if(event_list.TryGetValue(evt, out item)){
if (item != null) {
item.Invoke(parameter);
}
}
}
但在这种情况下,你会失去所有强类型方法的美感,你需要从对象中取消装箱。