我有一个非常简单的课程:
public delegate void ChangedEventHandler_OUT();
public class Plugin
{
public Plugin(string _pluginName)
{
pluginName = _pluginName;
}
public string pluginName;
public string member1;
public string member2;
public event ChangedEventHandler_OUT OnStatusChange1_OUT;
public event ChangedEventHandler_OUT OnStatusChange2_OUT;
public void PluginAction()
{
MessageBox.Show("ACtion from plugin " + pluginName);
}
}
在主要我创建两个实例并连接他们的事件:
var plugin1 = new Plugin("plugin1") { member1 = "AAA1", member2="BBB1"};
var plugin2 = new Plugin("plugin2") { member1 = "AAA1", member2 = "BBB1" };
plugin1.OnStatusChange1_OUT += plugin2.PluginAction;
现在我完全意识到这没什么意义,但我想深入思考并获得我能得到的所有信息:
MEMBERS
lbxInfo.Items.Add("Plugin1 member:");
Type type = typeof(Plugin);
foreach (var field in type.GetFields())
{
string strName = field.Name; // Get string name
string strType = field.FieldType.Name;
string strValue = (string)field.GetValue(plugin1);
lbxInfo.Items.Add(strType + " " + strName + " = " + strValue);
}
现在我想获得有关事件的所有信息:
事件:
lbxInfo.Items.Add("Plugin1 events:");
foreach (var ev in plugin1.GetType().GetEvents())
{
string strName = ev.Name;
string strType = ev.EventHandlerType.Name;
MethodInfo strConnectedTo = ev.GetAddMethod();
lbxInfo.Items.Add("Name = " + strName + " type =" + strType);
}
我无法做的部分是了解哪些事件与哪些事件有关。简而言之,我想添加一个部分,告诉我哪些事件与什么相关,哪些事情没有连接。类似的东西:
Plugin1 OnStatusChange1_Out connectedTo plugin2.PluginAction OnStatusChange1_Out connectedTo NULL
这显然必须通过反思和上面相同的foreach循环来完成。
提前感谢您的帮助 帕特里克
为Jeroen van Langen添加:
你写的作品。 我试图将提出的解决方案放在反射循环中:
public void CheckEventInfo(Plugin plg, ChangedEventHandler_OUT ev)
{
string invocationList = null;
if (ev != null)
foreach (var item in ev.GetInvocationList())
invocationList += item.Method.Name;
}
但是
lbxInfo.Items.Add("Plugin1 events:");
foreach (var ev in plugin1.GetType().GetEvents())
{
string strName = ev.Name;
string strType = ev.EventHandlerType.Name;
MethodInfo strConnectedTo = ev.GetAddMethod();
CheckEventInfo( plugin1,ev);<------NO!
lbxInfo.Items.Add("Name = " + strName + " type =" + strType);
}
所以这里我不知道要放什么,因为ev是一个eventinfo而不是ChangedEventHandler_OUT。 请你帮助我好吗?感谢
答案 0 :(得分:1)
使用plugin1.GetType().GetEvents()
只能获得事件的定义。像dotctor一样,你需要得到事件的InvocationList。从那里你可以获得一些实例信息。
以下是一个例子:
// This class will create an instance of the MainClass.
class Program
{
static void Main(string[] args)
{
MainClass mainClass = new MainClass();
mainClass.WhateverName = "MyClass2 main";
mainClass.Run();
Console.ReadLine();
}
}
// I'd rather use an interface
public interface IMyClassInfo
{
string WhateverName { get; set; }
}
// This mainclass will create a EventHandleClass which contains an event.
// This event is binded to the Class1_Example method.
public class MainClass : IMyClassInfo
{
internal void Run()
{
EventHandleClass eventHandleClass = new EventHandleClass();
eventHandleClass.Example += Class1_Example;
eventHandleClass.CheckEventInfo();
}
private void Class1_Example(object sender, EventArgs e)
{
Console.WriteLine("Class1_Example Method: ");
}
public string WhateverName { get; set; }
}
// this class holds the event, and when executing `CheckEventInfo()` the
// invocationlist is iterated and checkt if the target object is of type IMyClassInfo
public class EventHandleClass
{
public void CheckEventInfo()
{
if (Example != null)
foreach (var item in Example.GetInvocationList())
{
Console.WriteLine("GetInvocationList method:" + item.Method.Name);
Console.WriteLine("GetInvocationList class:" + item.Method.DeclaringType.FullName);
if (item.Target is IMyClassInfo)
{
Console.WriteLine("class2.WhateverName: " + ((IMyClassInfo)item.Target).WhateverName);
}
item.DynamicInvoke(this, EventArgs.Empty);
}
}
public event EventHandler Example;
}
我认为这应该足以创建自己的解决方案。
答案 1 :(得分:1)
我想你只想出于教育目的这样做。一般来说,如果你想知道特定事件是否有任何订阅者,或者更糟糕的是,确切地说是订阅者的列表,那么你就犯了一个架构错误。 (事件调用方法存在唯一的例外,它应该在调用之前检查事件委托是否为null。)
以下是如何获得所需结果的方法。
string GetSubscriptions(object o)
{
Type t = o.GetType();
// Obtain the collection of EventInfo's
var events = t.GetEvents();
if (events.Length == 0)
{
return "No events in " + t.Name;
}
string result = string.Empty;
foreach (var item in events)
{
result += "Event " + item.Name + ": ";
// Get the event's backing field description (FieldInfo)
var ed = t.GetField(item.Name, BindingFlags.Instance | BindingFlags.NonPublic);
if (ed == null)
{
throw new InvalidOperationException("Event backing field could not be obtained");
}
// Get the value of the backing field
var dl = ed.GetValue(o) as Delegate;
// If value is not null, then we've subscriptions
if (dl != null)
{
// Get the invocation list - an array of Delegate
var il = dl.GetInvocationList();
// This check is actually not needed, since the array should always contain at least 1 item
if (il.Length != 0)
{
// Use Target property of the delegate to get a reference to the object the delegate's method belongs to
result += string.Join("; ", il.Select(i => i.Target.GetType().Name + "." + i.Method.Name)) + Environment.NewLine;
continue;
}
}
result += "no subscriptions" + Environment.NewLine;
}
return result;
}
您必须记住,对于静态事件,Target
属性可以是null
。要获取静态事件,请将BindingFlags.Static
包含在GetField()方法的第二个参数中。