【问题标题】:Iterate through a Dictionary while modifying its Values (but not its Keys)迭代字典,同时修改它的值(但不是它的键)
【发布时间】:2021-03-30 03:18:42
【问题描述】:

还有一些其他问题涉及到这个主题,但似乎没有一个能解决它(或者,它们太复杂了,我无法理解......)

我有一个:

Private MCDevices As New Dictionary(Of IPAddress, MCDeviceInfo)

在这个Dictionary 中,IPAddress 是键(显然),MCDeviceInfo 是在别处定义的Classes。所以基本上是Dictionnary(Of IPAddress, Class)

我想通过MCDevices Dictionary 循环一个For ... Next,并在该循环中更改MCDeviceInfo Classes 的内容:在循环中,我更改KVP 的 ,但没有以任何方式在循环中添加、更改或删除IPAddress,我仔细检查了这一点。

For Each kvp As KeyValuePair(Of IPAddress, MCDeviceInfo) In MCDevices
' Some code changing the contents of the MCDeviceInfo but not the IPAddress
Next

仍然,到达Next,我得到了:

**System.InvalidIperationException:** 'Collection was modified; enumeration operation may not continue'.

这里的条件可能非常乐观,因为代码就停在那里...

有没有办法解决这个问题?为什么只要键不受影响,我就不能更改值?

【问题讨论】:

  • For ... Next, not For Each ... Next -- 你有办法将MCDeviceInfo 对象与IpAddress 键相关联吗?还是盲目的更改(只是更改MCDeviceInfo 中的值,与Key 无关)?
  • 如果你想改变一个集合的值,这个问题可能会对你有所帮助:How to iterate through Dictionary and change values? - 但它在 C# 中
  • 这是一个盲目的变化。 MCDeviceInfo 类甚至包含它们自己的 IP 地址字段,因此我确信我不必修改 KVPKeyFor...Next 可能有效,但看起来我必须将 Dictionary 转换为 SortedList,否则,我似乎无法通过 IPAddress 找到项目。
  • @JayV :我现在更加努力地将您提供的链接的 C# 转换为 VB,这似乎有效。我将发布我的 VB 代码作为答案(明天)-谢谢。
  • “在循环中,我更改了 KVP 的值”。这实际上是什么意思?这是否意味着您更改了已经存在的对象的属性,或者是否意味着您用不同的对象替换了该对象。它们是两个非常不同的东西。也许在导致问题的循环中显示实际代码。如果您想解决问题,最好显示导致问题的代码。

标签: vb.net dictionary for-loop collections invalidoperationexception


【解决方案1】:

可以更改这些值。考虑以下代码并将其与您的密码进行比较:

Imports System.Net

Module Module1

    Private MCDevices As New Dictionary(Of IPAddress, MCDeviceInfo)

    Public Class MCDeviceInfo
        Property Name As String
        Property Vegetarian As Boolean

        Public Overrides Function ToString() As String
            Return $"Name: {Name}"
        End Function
    End Class

    Sub Main()
        MCDevices.Add(IPAddress.Parse("1.1.1.1"), New MCDeviceInfo With {.Name = "Burger", .Vegetarian = False})
        MCDevices.Add(IPAddress.Parse("1.1.1.2"), New MCDeviceInfo With {.Name = "Beanburger", .Vegetarian = True})
        MCDevices.Add(IPAddress.Parse("1.1.1.3"), New MCDeviceInfo With {.Name = "Fries", .Vegetarian = True})

        For Each mcd In MCDevices
            If mcd.Value.Vegetarian Then
                mcd.Value.Name &= " Supersize"
            End If
        Next

        Console.WriteLine(String.Join(vbCrLf, MCDevices))
        Console.ReadLine()

    End Sub

End Module

输出:

[1.1.1.1, Name: Burger]
[1.1.1.2, Name: Beanburger Supersize]
[1.1.1.3, Name: Fries Supersize]

【讨论】:

  • 我相信这行得通;那意味着我不明白为什么它对我不起作用。在我的案例中代码太多,无法在这里全部复制。 (注意:超大号......一个非常美国的例子;-))
  • 我能看到的唯一区别是我替换了完整的Value Class,所以替换了完整的MCDeviceInfo(保留密钥),而不是仅仅更改 properties of类。
  • @CeSinge 看起来你有一个解决方案 - 问题是“修改它的值”,而不是“替换它的值”;)
【解决方案2】:

根据@AndrewMorton、@Jimi、@JayV 和@jmcilhinney 的意见,我现在认为 替换值,因此替换 MCDeviceInfo Classes,而不仅仅是更改它们的属性,可能是问题所在。

另外,我现在知道以下操作有效:

For Each kvp As KeyValuePair(Of IPAddress, MCDeviceInfo) In MCDevices
  ' Some code that changes the properties of the MCDeviceInfo Classes and even
  ' replaces them although the keys, the IPAddresses, are not touched in any way.
Next ' fails on the Next with the error mentioned in my question.

但以下确实有效(本质上是@Justin R.在他的回答中所写的翻译,@JayV 在他对我最初的问题的回答中):

Dim keys As List(Of IPAddress) = MCDevices.Keys.ToList
For Each key As IPAddress In keys ' Loop over the IPAddress , the keys of the KVP
  ' Some code that changes the properties of the MCDeviceInfo Classes and even
  ' replaces them.
Next

事实证明For Each 完全可以,就像普通的For...Next 一样。在第二个版本中,循环在一个完全独立的列表上,keys

【讨论】:

    猜你喜欢
    • 2011-10-10
    • 2021-07-01
    • 1970-01-01
    • 2021-09-12
    • 2023-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多