C# 使用foreach循环遍历字典,并获取具有值子集项的所有键/值对

C# 使用foreach循环遍历字典,并获取具有值子集项的所有键/值对,c#,asp.net-core-3.1,concurrentdictionary,C#,Asp.net Core 3.1,Concurrentdictionary,我有一个并发字典,我正在其中存储键/值对。这里的复杂性在于,值不是字符串或整数之类的单个对象,而是使用类模型添加的项的集合。在调试过程中,我似乎能够成功地将这些项添加到字典中,但问题是,当从另一个线程迭代字典时,我不知道如何读取这些项。我只想读取所有的键/值对,包括所有的项,并将它们添加到一个数组中,我可以通过JsonResult/Ajax将其传递给用户 我的AlarmEngine类别: public static ConcurrentDictionary<string, object&g

我有一个并发字典,我正在其中存储键/值对。这里的复杂性在于,值不是字符串或整数之类的单个对象,而是使用类模型添加的项的集合。在调试过程中,我似乎能够成功地将这些项添加到字典中,但问题是,当从另一个线程迭代字典时,我不知道如何读取这些项。我只想读取所有的键/值对,包括所有的项,并将它们添加到一个数组中,我可以通过JsonResult/Ajax将其传递给用户

我的AlarmEngine类别:

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; }
}
我的报警列表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);
}

如果在作为JSON数组返回给用户之前,最好通读整个字典并将所有键/值和子项存储到列表中,这对我来说也是一个可接受的解决方案,请记住,我希望尽可能高效地执行此操作,以尽量减少从一种形式转换到另一种形式的次数。项目将从其他线程添加和删除到字典中,但我的应用程序的这一特殊部分(即通过字典的迭代)仅用于只读目的,如果在阅读时内容发生了更改,对我来说并不重要,这只是将查询时相关/活动的报警列表放在一起。

如果这些资源在多个客户端/线程之间共享,并且大多数客户端正在读取。我想建议一个新的方案。它允许多个读卡器和一个写卡器

这样就可以并行生成JSON。ConcurrentX将资源传递给其他线程(如传递所有权或共享简单类型的数据)是非常有用的

private static ReaderWriterLockSlim cacheLock = new ReaderWriterLockSlim();

当字典没有更改时,甚至可以缓存json结果,但只有当出现问题时才应该这样做。

您需要将数据存储为正确的类,不要使用对象

您应该更改的一件事是不要将日期时间存储为字符串

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

嗨,Jeroen,我正在努力解决的问题是不知道如何访问循环中的值,因为它们不存储单个对象,如字符串或整数,键/值对将包含值项的子测试。示例Key=datetime,value={AlarmId,AlarmName,AlarmDescription}等这不是关于数据访问,而是关于安全访问数据。这就是为什么你需要一把单独的锁。ConcurrentDictionary仅在其集合上并发,而不在其包含的数据上并发。因此,请使用普通词典而不是并发词典。当您访问字典键中存储的任何信息时,值的甚至复杂对象都必须在readwriterlock中完成。在您创建json之后,可以释放锁。那么我们是说并发字典无法存储复杂对象吗?我选择concurrent dictionary的原因是多个线程将添加项目,多个线程需要读取内容。MVC控制器将只进行读取,但仍在从其他线程并发添加项。我需要看一些关于如何检索值项的示例代码,请看foreach循环部分的注释,谢谢,就像我说的,ConcurrentDictionary只在它的集合上安全,而不是在数据上。只有值类型的数据才是安全的,因为在读取数据时,它会创建一个副本。我只使用ConcurrentQueue或任何东西来放入一个项目,比如一堆火,然后在添加的线程中忘记它,永远不要碰它。其他线程可以读取信息。所以我认为ConcurrentDictionary不适合您的应用程序。当每个警报都添加到字典中时,它将永远不会被修改。唯一的行动将永远是添加一个新的报警字典,或干脆删除它从字典。这还会引起关注吗?啊,我现在明白了,我在字典中引用了一个泛型,而不是使用实际的类警报。我现在能够成功地解决价值项目,非常感谢您的帮助。您遇到的具体问题是什么?
[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();
}
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
}
public static ConcurrentDictionary<DateTime, Alarm> concurrentDictionary = new ConcurrentDictionary<DateTime, Alarm>();