保留EventHandler 的本地副本的原因是WPF 命令子系统在内部使用弱引用,因此我们需要保留对添加到CanExecuteChanged 事件的特定委托对象的引用。事实上,无论何时我们添加到任何指挥子系统事件中,我们也应该遵守这种做法,就像您对 SecurityTypeChanged 所做的那样。
您的问题的简短回答是canExecuteChangedHandler 可以是静态的,但您必须小心只初始化一次。它可以是静态的原因是,如果CanExecuteChanged 是静态的,所有new EventHandler(CanExecuteChanged) 都会做同样的事情。初始化一次的原因是不同的实例不同。
具有正确只读语义的私有属性是:
static EventHandler canExecuteChangedHandler
{
get
{
if (internalCanExecuteChangedHandler == null)
internalCanExecuteChangedHandler = new EventHandler(CanExecuteChanged);
return internalCanExecuteChangedHandler;
}
}
static EventHandler internalCanExecuteChangedHandler;
但这仅适用于CanExecuteChanged 是静态的。如果不是,则删除 static 限定符。无论哪种情况,您都必须小心使用该属性。
在此特定示例中,第二次调用 AddSecureCommand 第一次调用canExecuteChangedHandler 有被垃圾收集的风险。
最后,如果这一切听起来像黑魔法,这里有一个代码示例来说明正在发生的事情。
public class Container
{
private WeakReference reference;
public object Object
{
get { return reference.IsAlive ? reference.Target : null; }
set { reference = new WeakReference(value); }
}
}
public class DelegateTest
{
private EventHandler eventHandler;
private Container container1;
private Container container2;
void MyEventHandler(object sender, EventArgs args)
{
}
public DelegateTest()
{
this.eventHandler = new EventHandler(MyEventHandler);
this.container1 = new Container { Object = this.eventHandler };
this.container2 = new Container { Object = new EventHandler(MyEventHandler) };
GC.Collect();
Console.WriteLine("container1: {0}", this.container1.Object == null);
Console.WriteLine("container2: {0}", this.container2.Object == null);
}
}
这会产生这个输出:
container1: False
container2: True
这表明在垃圾收集期间,第二个容器的EventHandlergarbage-collected “从它下面出来”。这是设计使弱引用的工作方式以及您需要自己保留对它的引用的解释。