进行基于组件的开发,我发现自己经常这样做:
public class SomeClass
{
SomeOtherClass foo;
public SomeOtherClass Foo
{
get { return foo; }
set {
if (value != foo) {
if (value != null) {
// subscribe to some events
value.SomeEvent += foo_SomeEvent;
}
if (foo != null) {
// unsubscribe from subscribed events
foo.SomeEvent -= foo_SomeEvent;
}
foo = value;
}
}
}
void foo_SomeEvent(object sender, EventArgs e)
{
// do stuff
}
}
有没有更优雅的方式来做这个事件“换出”?
(当然,如果foo
是不可变的,那么可以避免整个问题,但是我不会得到任何视觉设计师支持。)
答案 0 :(得分:5)
我认为您当前的实施是完全可以接受的。它非常清晰易懂。
如果你想缩短代码,因为你做了很多,你可以制定一个方法来实现它:
private void SwapEventHandler<T>(T a, T b, Action<T> subscribe, Action<T> unsubscribe)
where T : class
{
if (a != null)
subscribe(a);
if (b != null)
unsubscribe(b);
}
然后你可以写:
if (value != foo)
{
SwapEventHandler(value,foo, (o) => o.SomeEvent += foo_SomeEvent, (o) => o.SomeEvent -= foo_SomeEvent );
foo = value;
}
答案 1 :(得分:1)
你正在做的事情很好,但我通常更喜欢在订阅新事件之前取消订阅旧事件处理程序的惯例,只是为了避免两个对象都试图处理的任何潜在的“重叠”如果它从调用之间的另一个线程触发,则为同一事件。
为了获得微小的改进,您可以省去不必要的大括号,使代码更紧凑,更“整洁”(“更整洁”在旁观者眼中)。
set { if (value != foo) { if (foo != null) foo.SomeEvent -= foo_SomeEvent; if (value != null) value.SomeEvent += foo_SomeEvent; foo = value; } }
如果你使用空引用是非法的(例如通过使用对“Null Foo对象”的引用而不是null),那么你可以完全省略ifs:
set { if (value != foo) { foo.SomeEvent -= foo_SomeEvent; value.SomeEvent += foo_SomeEvent; foo = value; } }
在某些情况下,您有许多属性处理类似的对象/事件,您可能还可以在(通用)帮助器方法中实现交换代码,以便在一个位置实现实现,并且您的属性都只是调用共享帮助程序方法。如果您可以共享许多属性的一个实现,那么这只会有好处:
set { Helpers.SetValueAndResubscribeFooSomeEvent(ref foo, value); }
答案 2 :(得分:0)
如果您不知道哪些事件已在活动中注册,并且想要完整地清除它,您可以执行以下操作:
public class SomeOtherClass
{
public event EventHandler SomeEvent;
public void ClearSomeEvent()
{
foreach (EventHandler e in SomeEvent.GetInvocationList())
{
SomeEvent -= e;
}
}
}
在SomeClass.Foo属性设置器中:
if (foo != null)
{
// unsubscribe from subscribed events
foo.ClearSomeEvent();
}
如果您确实知道所描述的代表,那么您当前的解决方案就可以了。