退订然后订阅 Console.CancelKeyPress
unsubscribe then subscribe to Console.CancelKeyPress
我注意到订阅然后取消订阅 Console.CancelKeyPress 会使下一次订阅失败。
更奇怪的是:从一个空的事件处理程序开始修复这个问题。
有人可以解释这种行为吗?
class Program
{
static void Main(string[] args)
{
Console.TreatControlCAsInput = false;
// 2: uncomment following for an unexpected fix...
//Console.CancelKeyPress += (s, a) => { };
Console.CancelKeyPress += Handler_1;
Console.WriteLine("Press Ctr+C to prove that Handler_1 cancels key press.");
Console.ReadLine();
Application.DoEvents(); // make sure events are handled before unsubscribe
Console.CancelKeyPress -= Handler_1;
// 1: uncomment following to prove failure...
//Console.CancelKeyPress += Handler_2;
//Console.WriteLine("Press Ctr+C to prove that Handler_2 cancels key press.");
//Console.ReadLine();
Application.DoEvents(); // make sure events are handled
Console.WriteLine("End of demo, type something to prove application is still responsive.");
Console.ReadLine();
}
private static void Handler_1(object sender, ConsoleCancelEventArgs args)
{
args.Cancel = true;
Console.WriteLine("Key press is canceled by Handler_1");
}
private static void Handler_2(object sender, ConsoleCancelEventArgs args)
{
args.Cancel = true;
Console.WriteLine("Key press is canceled by Handler_2");
}
}
这是 CancelKeyPress 实现中的一个错误
public static event ConsoleCancelEventHandler CancelKeyPress {
[System.Security.SecuritySafeCritical] // auto-generated
[ResourceExposure(ResourceScope.Process)]
[ResourceConsumption(ResourceScope.Process)]
add {
new UIPermission(UIPermissionWindow.SafeTopLevelWindows).Demand();
lock(InternalSyncObject) {
// Add this delegate to the pile.
_cancelCallbacks += value;
// If we haven't registered our control-C handler, do it.
if (_hooker == null) {
_hooker = new ControlCHooker();
// BUG: after you unsubscribe from CancelKeyPress it becomes null
// and when you subscribe to CancelKeyPress again the call below will never be called. In the Remove part they will not set _hooker to null.
_hooker.Hook();
}
}
}
[System.Security.SecuritySafeCritical] // auto-generated
[ResourceExposure(ResourceScope.Process)]
[ResourceConsumption(ResourceScope.Process)]
remove {
new UIPermission(UIPermissionWindow.SafeTopLevelWindows).Demand();
lock(InternalSyncObject) {
// If count was 0, call SetConsoleCtrlEvent to remove cb.
_cancelCallbacks -= value;
Contract.Assert(_cancelCallbacks == null || _cancelCallbacks.GetInvocationList().Length > 0, "Teach Console::CancelKeyPress to handle a non-null but empty list of callbacks");
if (_hooker != null && _cancelCallbacks == null)
_hooker.Unhook();
//BUG: It Unhooks but does not set _hooker to null.
}
}
}
我注意到订阅然后取消订阅 Console.CancelKeyPress 会使下一次订阅失败。
更奇怪的是:从一个空的事件处理程序开始修复这个问题。
有人可以解释这种行为吗?
class Program
{
static void Main(string[] args)
{
Console.TreatControlCAsInput = false;
// 2: uncomment following for an unexpected fix...
//Console.CancelKeyPress += (s, a) => { };
Console.CancelKeyPress += Handler_1;
Console.WriteLine("Press Ctr+C to prove that Handler_1 cancels key press.");
Console.ReadLine();
Application.DoEvents(); // make sure events are handled before unsubscribe
Console.CancelKeyPress -= Handler_1;
// 1: uncomment following to prove failure...
//Console.CancelKeyPress += Handler_2;
//Console.WriteLine("Press Ctr+C to prove that Handler_2 cancels key press.");
//Console.ReadLine();
Application.DoEvents(); // make sure events are handled
Console.WriteLine("End of demo, type something to prove application is still responsive.");
Console.ReadLine();
}
private static void Handler_1(object sender, ConsoleCancelEventArgs args)
{
args.Cancel = true;
Console.WriteLine("Key press is canceled by Handler_1");
}
private static void Handler_2(object sender, ConsoleCancelEventArgs args)
{
args.Cancel = true;
Console.WriteLine("Key press is canceled by Handler_2");
}
}
这是 CancelKeyPress 实现中的一个错误
public static event ConsoleCancelEventHandler CancelKeyPress {
[System.Security.SecuritySafeCritical] // auto-generated
[ResourceExposure(ResourceScope.Process)]
[ResourceConsumption(ResourceScope.Process)]
add {
new UIPermission(UIPermissionWindow.SafeTopLevelWindows).Demand();
lock(InternalSyncObject) {
// Add this delegate to the pile.
_cancelCallbacks += value;
// If we haven't registered our control-C handler, do it.
if (_hooker == null) {
_hooker = new ControlCHooker();
// BUG: after you unsubscribe from CancelKeyPress it becomes null
// and when you subscribe to CancelKeyPress again the call below will never be called. In the Remove part they will not set _hooker to null.
_hooker.Hook();
}
}
}
[System.Security.SecuritySafeCritical] // auto-generated
[ResourceExposure(ResourceScope.Process)]
[ResourceConsumption(ResourceScope.Process)]
remove {
new UIPermission(UIPermissionWindow.SafeTopLevelWindows).Demand();
lock(InternalSyncObject) {
// If count was 0, call SetConsoleCtrlEvent to remove cb.
_cancelCallbacks -= value;
Contract.Assert(_cancelCallbacks == null || _cancelCallbacks.GetInvocationList().Length > 0, "Teach Console::CancelKeyPress to handle a non-null but empty list of callbacks");
if (_hooker != null && _cancelCallbacks == null)
_hooker.Unhook();
//BUG: It Unhooks but does not set _hooker to null.
}
}
}