使用 foreach 循环遍历字典并获取所有具有值子集项的 key/value 对

Iterate through dictionary with foreach loop and fetch all key/value pairs with value subset items

我有一个并发字典,我正在其中存储 key/value 对。这里的复杂性在于值不是单个对象,如字符串或整数,它们是使用 class型号。看起来调试,我能够成功地将项目添加到字典中,但我遇到的问题是不知道如何从另一个线程遍历字典时读取这些项目。我只是想读取所有 key/value 对,包括所有项目并将它们添加到一个数组中,我可以通过 JsonResult/Ajax.

传回给用户

我的报警引擎Class:

public static ConcurrentDictionary<string, object> concurrentDictionary = new ConcurrentDictionary<string, object>();

public class Alarm
{
    public int AlarmId { get; set; }
    public string AlarmName { get; set; }
    public string AlarmDescription { get; set; }
    public string ApplicationRoleId { get; set; }
    public DateTime DateTimeActivated { get; set; }
}

摘自我向字典中添加项目的方法:

concurrentDictionary.TryAdd(DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss"), new Alarm 
                {
                    DateTimeActivated = DateTime.Now,
                    ApplicationRoleId = applicationRoleId,
                    AlarmId = alarmId,
                    AlarmName = alarmName,
                    AlarmDescription = description,
                }); // I'm using datetime as the key as this is unique form each key/value pair added.

我的 AlarmList MVC 控制器:

[HttpGet]
public Task<IActionResult> FetchAlarmsListAsync()
{

    // Enumeration is thread-safe in ConcurrentDictionary.
    foreach (var item in AlarmEngine.concurrentDictionary)
    {
        // How do I access the key and value pairs here?
        // Note each value contains a subset of items
        // i want to access all items stored
    }

    return new JsonResult(Array containing all keys and value items);
}

如果最好通读整个字典并将所有 keys/value(带有子项)存储到列表中,然后再作为 JSON 数组返回给用户,这将是一个可以接受的解决方案对我来说也是如此,请记住,我想尽可能高效地执行此操作,以尽量减少从一种形式转换为另一种形式的次数过多。项目将从其他线程添加到字典或从字典中删除,但我的应用程序的这个特殊部分,即遍历字典只是为了只读目的,如果内容在阅读时发生变化对我来说并不重要,它是只是为了在查询时汇总一个警报列表 relevant/active。

如果这些资源在多个 clients/threads 之间共享,并且大多数客户都在阅读。我建议 ReaderWriterLockSlim。它允许多个读者和一个作者。

这样 json 可以并行生成。 ConcurrentX 可用于将资源传递给其他线程 (如传递所有权) 或只是 share 简单类型数据。

private static ReaderWriterLockSlim cacheLock = new ReaderWriterLockSlim();

[HttpGet]
public Task<IActionResult> FetchAlarmsListAsync()
{
    cacheLock.EnterReadLock();
    try
    {
        // Enumeration is thread-safe in Dictionary.
        foreach (var item in AlarmEngine.normalDictionary)
        {
            // How do I access the key and value pairs here?
            // Note each value contains a subset of items
            // i want to access all items stored
        }

        return new JsonResult(Array containing all keys and value items);
    }
    finally
    {
        cacheLock.ExitReadLock();
    }
}

cacheLock.EnterWriteLock();
try
{
    normalDictionary.TryAdd(DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss"), new Alarm 
    {
        DateTimeActivated = DateTime.Now,
        ApplicationRoleId = applicationRoleId,
        AlarmId = alarmId,
        AlarmName = alarmName,
        AlarmDescription = description,
    }); // I'm using datetime as the key as this is unique form each key/value pair added.
}
finally
{
    cacheLock.ExitWriteLock();
}

甚至可以在不更改字典的情况下缓存 json 结果,但只有在出现问题时才应该这样做。

您需要将数据存储为正确的class,请勿使用object

public static ConcurrentDictionary<string, Alarm> concurrentDictionary = new ConcurrentDictionary<string, Alarm>();
//                                          ^^^ 

public class Alarm
{
    public int AlarmId { get; set; }
    public string AlarmName { get; set; }
    public string AlarmDescription { get; set; }
    public string ApplicationRoleId { get; set; }
    public DateTime DateTimeActivated { get; set; }
}

现在您可以访问警报的属性。

// Enumeration is thread-safe in Dictionary.
foreach (var item in AlarmEngine.concurrentDictionary)
{
    Trace.WriteLine(item.Key);  // which is the datetime
    Trace.WriteLine(item.Value.AlarmName);
    // How do I access the key and value pairs here?
    // Note each value contains a subset of items
    // i want to access all items stored
}

您应该更改的一件事是不要将 DateTime 存储为字符串。

public static ConcurrentDictionary<DateTime, Alarm> concurrentDictionary = new ConcurrentDictionary<DateTime, Alarm>();