c# - 从未插入的字典键中的空值
问题描述
在下面的代码中,我插入了一些虚拟代码来检查 null 并删除它们只是为了尝试了解正在发生的事情。我仍然不明白为什么我的问题会发生:)
我有以下将值插入字典:
private Dictionary<string, DateTimeOffset> _keys = new Dictionary<string, DateTimeOffset>();
public async Task NotifyAsync(DateTimeOffset key)
{
if (key==null)
{
this._logger.LogError("Recieved null key");
return;
}
var dictKey = RadarContext.TrimTimeToPartitionBin(key, TimeSpan.FromMinutes(1));
if (string.IsNullOrEmpty(dictKey))
{
this._logger.LogError("Recieved null dictKey for {time}",key);
return;
}
_keys[dictKey] = key;
await this.SetLastUpdatedAsync(DateTimeOffset.UtcNow);
}
没有其他插入。
然后我有以下内容,稍后会在键上循环
foreach(var key in _keys.Keys.Where(k => string.IsNullOrEmpty( k )).ToArray())
{
_logger.LogError("Removed null key: {time}",_keys[key]);
_keys.Remove(key);
}
foreach (var key in _keys.Keys.OrderByDescending(key=> RadarContext.FromTrim(key,_logger)).Take(100).ToArray())
{
if (_keys[key] < tminus1)
{
await actionblock.SendAsync(key);
}
}
我的问题是我在RadarContext.FromTrim
public static DateTimeOffset FromTrim(string trim, ILogger logger = null)
{
try
{
var ticks = long.Parse(trim);
return new DateTimeOffset(DateTimeOffset.MaxValue.UtcTicks - ticks, TimeSpan.Zero);
}
catch(Exception ex)
{
if (logger != null)
logger.LogError(ex, "Failed to convert from {trim}", trim);
throw;
}
}
错误如下:
2019-03-05 23:15:21.922 +01:00 [ERR] Failed to convert from null
System.ArgumentNullException: Value cannot be null.
Parameter name: s
at System.Int64.Parse(String s)
at Ascend.Wammo.RadarIngestor.ServiceProvider.RadarContext.FromTrim(String trim, ILogger logger) in C:\dev\AscendXYZ\Ascend.Wammo.RadarIngestor\apps\Ascend.Wammo.RadarIngestor.ServiceProvider\RadarContext.cs:line 493
在这里给定的代码怎么可能在_keys.Keys.OrderByDescending(key=> RadarContext.FromTrim(key,_logger))
从不插入空值的情况下循环时给 FromTrim 一个空值。
解决方案
问题是您Dictionary<TKey, TValue>
从多个线程中使用,这不是它的目的。大概在一个线程中对内部状态的一些修改导致在另一个线程中看到一个空键。
ConcurrentDictionary<TKey, TValue>
旨在用于多个线程 - 但我仍然会避免以您目前正在做的方式使用它。现在,您正在遍历键并分别查找每个键。我会遍历这些条目:
var entries = _keys
.OrderByDescending(entry => RadarContext.FromTrim(entry.Key, _logger))
.Take(100)
.ToArray();
foreach (var entry in entries)
{
if (entry.Value < tminus1)
{
await actionblock.SendAsync(entry.Key);
}
}
这样您就可以获得一致的快照。
推荐阅读
- go - Godoc:将文档限制为项目(不是依赖项)
- angular - 带有 NGFOR 的材料扩展面板似乎锁定了我的 js 资源
- laravel - 使用 btable 将事件传输到父组件
- conda - 如何通过 Conda 安装 hla-la 包?
- javascript - 如何在 console.log 中用引号显示字符串输出?
- c++ - C++ SQLite3 Bind-Blob 未按预期工作
- python - 在 psycopg2 中设置 callproc 方法的限制
- c# - 用户的 C# 和 ASP.NET MVC 运行时超时
- c++ - Antlr4 空字符串匹配异常
- python - 在一个文件中使用基于特定(开始日期和结束日期)的周数在主目录中搜索匹配项