c# - 在 WPF 应用程序中锁定字典访问
问题描述
我正在开发一个旧的大型 WPF 应用程序。客户报告了一个错误,他们能够重现,但我不能。应用程序中有一个类,如下所示:
public static class PermissionProvider
{
private static Dictionary<string, bool> Permissions;
public static void Init()
{
Permissions = new Dictionary<string, bool>();
}
private static object _lock = new object();
public static bool HasPermission(string permission)
{
if (string.IsNullOrEmpty(permission)) return false;
lock (_lock)
{
if (Permissions.ContainsKey(permission)) return Permissions[permission];
var hasPermission = true; // Expensive call a third party module to check user permissions.
Permissions.Add(permission, hasPermission);
return hasPermission;
}
}
}
根据客户提供的日志文件,该行Permissions.Add(permission, hasPermission)
抛出了一个ArgumentException
(key already exists)。这对我来说没有意义;代码检查同一锁内的钥匙。
根据测试运行,所有调用HasPermission
似乎都是从主线程进行的。该程序Dispatcher.BeginInvoke
在地方使用,但我的理解是锁定甚至不是必需的。字典是私有的,不能从其他任何地方访问。
在什么情况下会发生这种异常?
我的第一个想法是客户正在运行旧版本的应用程序,但事实证明这个类只是在最新版本中添加的。
这个特殊的异常应该很容易通过更改 to 来避免Permissions.Add(permission, hasPermission)
,Permissions[permission] = hasPermission
但我更愿意先了解它为什么会发生。
解决方案
这是可能的,但如果没有完整的源代码就很难说。
昂贵的电话
var hasPermission = true; // Expensive call a third party module to check user permissions.
可以做一些再次调用的事情HasPermission()
。因此,相同的线程将进入
lock (_lock) { ... }
再次(这是允许的),可能添加许可,离开锁,离开方法并返回到HasPermission()
它来自的地方,再次添加相同的密钥。
这可能需要在您的客户处进行生产调试。如果您对此不熟悉并且可以说服您的客户暂时替换受影响的 DLL(让他创建一个备份副本),您可以尝试以下操作:
lock (_lock)
{
var stack = Environment.StackTrace;
if (stack.Split(new []{nameof(HasPermission)}, StringSplitOptions.None).Length> 2) throw new Exception("I should not be in here twice");
...
}
这应该会使应用程序崩溃(除非某个地方的通用 catch 块),其调用堆栈具有两次受影响的方法,因此您可以分析第二次调用的来源。在这种情况下做任何你想做的事情:生成故障转储,分析你的日志,......
生成堆栈跟踪非常昂贵,因此这将改变时间并因此可能使问题消失。但是,消失的问题并不是固定的问题。
推荐阅读
- botframework - 机器人可以改变初始消息的外观吗?
- r - 在 R 中连续总结 2 次是否正确?
- ios - SwiftUI NavigationView 嵌套栏问题
- excel - 如何解决 Visual Basic 中的对象定义错误?
- msmq - Windows 功能“Microsoft 消息队列 (MSMQ) 服务器”未显示在 Windows 10 机器中
- configuration - SharePoint Online Web 部件 - 全局属性/配置
- sql - 如何将具有 yyyymm 值的 nvarchar 转换为日期?
- c++ - 如何在 Gradle 中禁用本机项目的开发(调试)二进制文件?
- r - 如何在 R 上从价格时间序列中创建 300 只等权重股票的投资组合并对投资组合进行回测?
- javascript - 这个例子中的 onToggle 属性是如何工作的?