gpt4 book ai didi

c# - Hook 到列表中所有对象的事件

转载 作者:太空狗 更新时间:2023-10-29 21:36:06 27 4
gpt4 key购买 nike

问题:我发现自己经常想要处理一组对象的事件。在集合中添加和删除对象时,每个对象都必须 Hook 或取消 Hook 。我发现使用相同的事件 Hook 代码来设计每个执行此操作的类是乏味且重复的。

所需的解决方案:所以,我正在尝试想出类似 EventBindingList 的东西。 , 其中包含可挂接的对象,并允许用户一次挂接多个对象,以及添加和删除列表中的对象。

为了保持通用性,需要用到Reflection。在列表的构造函数中,用户可以通过 EventInfo 或事件名称指定正在挂接的事件。这似乎是最简单的方法。

    private EventInfo _info;

public EventBindingList(string EventName)
{
_info = typeof(T).GetEvents().Where(e => e.Name == EventName).First();
}

public EventBindingList(EventInfo info)
{
_info = info;
}

我已经尝试了几种方法,但我仍然对方法、委托(delegate)、lambda 和 EventHandler 之间的差异有疑问。

失败的解决方案 1:

我尝试过的一个解决方案是使用自定义事件访问器,但没有奏效。这将是列表中包含要 Hook 的对象的事件。这是因为,在添加 EventHandler 时,会抛出 ArgumentException:Object of type 'System.EventHandler' cannot be converted to type 'ExternalProject.CustomEventHandler'.我尝试将 EventHandler 强制转换为正确的类型(使用通用类型参数,因为这是外部项目的事件处理程序),但强制转换会失败。

    public event EventHandler ElementEvent
{
add
{
_handlers.Add(value);
foreach (T t in this)
{
_info.AddEventHandler(t, value);
}
}
remove
{
foreach (T t in this)
{
_info.RemoveEventHandler(t, value);
}
_handlers.Remove(value);
}
}

失败的解决方案 2:

我还没有找到让列表本身处理事件然后为任何订阅者调用委托(delegate)的好方法。我发现尝试使用反射来添加事件处理程序需要委托(delegate)。在我的测试中,我找不到保留事件参数并将这些参数也传递给订阅者的方法

请求:对于如何实现这一目标,是否还有其他想法?

最佳答案

编辑:

public abstract class ManagedEventCollection<T,TEventArgs> : IList<T>
{
private EventInfo m_event;
public ManagedEventCollection(string eventName)
{
m_list = new ObservableCollection<T> ();
m_list.CollectionChanged += CollectionChanged;
m_event = typeof (T).GetEvent (eventName);
}
// Add/Remove/Indexer/Clear methods alter contents of m_list.

public EventHandler<TEventArgs> Handler{get;set;}

protected abstract void OnItemAdded(T item);
protected abstract void OnItemRemoved(T item);

private void CollectionChanged(object sender, NotifyCollectionChangedEventArgs ea)
{
foreach (T item in ea.NewItems)
{
m_event.AddEventHandler (
item,
Delegate.CreateDelegate (m_event.EventHandlerType, item, Handler.Method));
}
foreach (T item in ea.OldItems)
{
m_event.RemoveEventHandler (
item,
Delegate.CreateDelegate (m_event.EventHandlerType, item, Handler.Method));
}
}
}

原答案:您可以使用 ObservableCollection<T> .这个类有一个 CollectionChanged您可以根据需要订阅/取消订阅的事件。

我会创建一个基类(这是凭内存,只是为了理解这一点)。

public abstract class ManagedEventCollection<T> : IList<T>
{
public ManagedEventCollection()
{
m_list = new ObservableCollection<T> ();
m_list.CollectionChanged += CollectionChanged;
}
... // Add/Remove/Indexer/Clear methods alter contents of m_list.
protected abstract void OnItemAdded(T item);
protected abstract void OnItemRemoved(T item);

private ObservableCollection<T> m_list;
private void CollectionChanged(object sender, NotifyCollectionChangedEventArgs ea)
{
foreach (T item in ea.NewItems)
OnItemAdded(item);
foreach (T item in ea.OldItems)
OnItemRemoved(item);
}
}

然后,您的派生类型可以这样做:

public class DogManagedEventCollection : ManagedEventCollection<Dog>
{
protected override OnItemAdded (Dog dog)
{
dog.Bark += Bark;
}
protected override OnItemRemoved (Dog dog)
{
dog.Bark -= Bark;
}

private void Bark(object sender, BarkEventArgs ea){...}
}

如果你真的想要,你也可以订阅反射,但这会更容易出错,而且不那么容易阅读/维护/理解。

关于c# - Hook 到列表中所有对象的事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6653716/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com