【问题标题】:Writing a Dictionary("Entry").clone()编写字典("Entry").clone()
【发布时间】:2017-03-27 16:39:07
【问题描述】:

我有一个班级叫ReDictionary

编辑:我的班级声明

Public Class ReDictionary(Of TKey, TValue) Inherits Dictionary(Of TKey, TValue)

它为我的字典目的提供了一些小的改进。

' Wraps TryGetValue
Public Function ValueOr(key, OnNoValue)
    dim TossBool = Me.TryGetValue(key, TossObj)
    If TossBool Then
        Return TossObj
    Else
        Return OnNoValue
    End If
End Function

我正在尝试编写 .Clone() 方法(浅)作为课程的一部分。

我尝试了一个使用TopLevelDictionary.clone(src,dest) 语法的函数 和一个使用TopLevelDict("Entry").Clone(src) 语法的sub

Public Sub Clone(srcKey As TKey, destKey As TValue) As ReDictionary(Of object, object)
    Dim newbook As New ReDictionary(Of Object, Object)
    For Each kvp As KeyValuePair(Of Object, Object) In Me(srcKey)
        newbook(kvp.Key) = kvp.Value.ToString()
    Next
    Me(destKey) = newbook
End Sub

这几乎是一个准代码。我可能已经尝试过TKey/TValueObject/Object 的所有组合,甚至是我想要克隆的两个字典恰好是 String/String 的特定组合。我也试过不指定参数/返回类型

我通常得到的错误是Cannot Convert ReDictionary(...) to ReDictionary(...),例如当函数临时 ReDictionary 是 (Object, Object) 而源 ReDictionary 是 (String, String) 时。

我想避免将我的公共字典设为(Object, Object),因为这似乎很浪费内存。

我的两个字典在表单加载时填充在同一个函数中。一个是公共的,另一个是函数本地的,但传递值(由语言选择的描述)全局字典。

我意识到我可以很容易地编写一个克隆函数(不是ReDictionary 的一部分,它使用了Dict(NewEntry) = CloneEntry(Dict("Entry") 之类的语法。我之前尝试在公共字典中克隆对象时遇到过类似的情况。

Private Function CloneObj(key) As ReDictionary(Of String, String)
    Dim inObj = New ReDictionary(Of String, String)
    For Each kvp As KeyValuePair(Of String, String) In pLib(key)
        inObj(kvp.Key) = pLib(key)(kvp.Key)
    Next
    Return inObj
End Function

虽然我在尝试放松对象类型时可能会遇到冲突。

  • 全局字典是Dictionary(String) of Dictionaries(String) of Strings
  • 本地字典是Dictionary(String) of cTranslations(class) with String properties

到那时,两个函数都可以做到,但我只是更加坚定,如果可能的话。


更新:这是我目前正在尝试使用的版本

Public Class ReDictionary(Of TKey, TValue)
    Inherits Dictionary(Of TKey, TValue)
    Public Function Clone(srcKey As Object) As ReDictionary(Of TKey, TValue)
        Dim inObj As New ReDictionary(Of TKey, TValue)
        For Each kvp As KeyValuePair(Of TKey, TValue) In Me
            inObj(kvp.Key) = kvp.Value
        Next
        Return inObj
    End Function
End Class

这是该语法的示例用法。

Dim Films As New ReDictionary(Of String, ReDictionary(Of String, String)
Films("Edge of Tomorrow") = New ReDictionary(Of String, String)
Films("Edge of Tomorrow")("Description") = "Tom Crues goes to war on Groundhog's Day"
Films("Live, Die, Repeat") = Films.Clone("Edge of Tomorrow")

Films("Birdman") = New ReDictionary(Of String, String)
Films("Birdman")("Description") = "Michael Keyton, who played a superhero 20 years ago, plays an actor who also did"
Films("The Unexpected Virtue of Ignorance") = Films.Clone("Birdman")

我实际上更改了一些克隆项目的一些属性,这就是为什么我需要克隆而不是仅将一个条目作为对兄弟条目的引用。

函数本身实际上并没有导致任何错误,但是当我尝试使用它时,我得到(直接从调试器复制,只是缩进以便于阅读):

错误很明显

Value of type 'ReDictionary(Of String, ReDictionary(Of String, String))' cannot be converted to 'ReDictionary(Of String, String)

如果我将In Me 更改为In Me(srckey),我会得到

Expression of type TValue which is not a collection type.

将 srcKey 的类型更改为 TValueTKey 也会导致错误,删除 srckey 的类型也是如此。

【问题讨论】:

  • 所以克隆方法是克隆另一个ReDictionary 内部的ReDictionary?对吗?
  • 我不太了解您的问题,无法给出答案,但我原以为浅克隆方法会有类似 Clone() As ReDictionary(Of TKey, TValue) 的签名,假设您有一个类 ReDictionary(Of TKey, TValue) .此外,像您的 ValueOr 函数这样的方法可以编写为标准通用 Dictionary(或者,更好的是 IDictionary)上的扩展方法,这可能消除对自定义字典类的需要。
  • 我很难理解您要完成的工作。如果您可以发布有关您如何尝试使用它的代码 sn-p,它可能会有所帮助。您只是想实现字典Clone 并遇到打字问题还是Clone 执行某些特殊功能?顶级字典的类型是什么? ReDictionary(Of String, ReDictionary(Of String, String))?这是另一篇文章,展示了如何克隆普通字典(琐碎)stackoverflow.com/questions/2279619/…
  • @Joe 我用一个人为的例子更新了我的问题。我肯定明白您对ValueOr 的看法,并会对此进行调查,但我也想了解为什么这不起作用。 Base Dictionary 的方法独立于类型工作,我想了解如何。 感谢您的宝贵时间。
  • @Joe 好吧,你是对的,扩展方法似乎是最好的方法。我自己将其发布为答案,以防有人发现它有用。

标签: vb.net dictionary


【解决方案1】:

首先,我想指出的是,您可能应该制作对象而不是使用字典,但我离题了。

那么,为什么它不起作用。

首先,让我们看看Clone函数

Public Class ReDictionary(Of TKey, TValue)
    Inherits Dictionary(Of TKey, TValue)
    Public Function Clone(srcKey As Object) As ReDictionary(Of TKey, TValue)
        Dim inObj As New ReDictionary(Of TKey, TValue)
        For Each kvp As KeyValuePair(Of TKey, TValue) In Me
            inObj(kvp.Key) = kvp.Value
        Next
        Return inObj
    End Function
End Class

请注意从未使用过 srcKey。所以这个函数返回的是你调用它的ReDictionary的一个克隆,不是包含在TopLevel(srcKey)中的ReDictionary

接下来,让我们看看你是如何使用它的。

Dim Films As New ReDictionary(Of String, ReDictionary(Of String, String)
Films("Edge of Tomorrow") = New ReDictionary(Of String, String)
Films("Edge of Tomorrow")("Description") = "Tom Crues goes to war on Groundhog's Day"
Films("Live, Die, Repeat") = Films.Clone("Edge of Tomorrow")

如上所述,Films.Clone 将返回与调用ReDictionary 相同类型的ReDictionary,这意味着您正在尝试将ReDictionary(Of String, ReDictionary(Of String, String) 分配给Films("Live, Die, Repeat"),其类型为ReDictionary(Of String, String)

这两个显然是不同的类型,因此你不能做那个作业。

那么需要修复什么:

Clone 方法

我建议您删除 srcKey 参数并使用此方法克隆您正在调用它的对象(这是它已经在做的)

用法

现在,因为Clone 将克隆您调用它的字典,您可以执行以下操作:

Dim Films As New ReDictionary(Of String, ReDictionary(Of String, String)
Films("Edge of Tomorrow") = New ReDictionary(Of String, String)
Films("Edge of Tomorrow")("Description") = "Tom Crues goes to war on Groundhog's Day"
Films("Live, Die, Repeat") = Films("Edge of Tomorrow").Clone()

【讨论】:

  • 我真的很感谢您的反馈srckey 没有在那个化身中使用(因为我尝试的一切都在尝试时遇到语法错误,所以我很生气而犯了一个错误in Me(srcKey) 之类的东西,这是导致类型冲突的最初目的。
【解决方案2】:

正如 Joe 在 cmets 中所说,扩展方法最终效果最好,但看不出没有try/catchif/else 的通用类型。

我找到了Dim Args as type() = SourceDict.GetType().GetGenericArguments(),但由于我不能将变量用于对象类型,例如Dim inObject As New Dictionary(Of Args(0), Args(1)),因此似乎需要重复。

留在这里以防它对任何人有帮助

Public Module DictionaryExtensions '(Of Tkey, TValue)
    <Extension()>
    Public Function CloneDict(ByVal SourceDict As Object,
                       ByVal SourceKey As String) As IDictionary
        Try
            Dim inObject As New Dictionary(Of String, String)
            For Each kvp As KeyValuePair(Of String, String) In SourceDict(SourceKey)
                inObject(kvp.Key) = SourceDict(SourceKey)(kvp.Key)
            Next
            Return inObject
        Catch
            Dim inObject As New Dictionary(Of String, Translation)
            For Each kvp As KeyValuePair(Of String, Translation) In SourceDict(SourceKey)
                inObject(kvp.Key) = SourceDict(SourceKey)(kvp.Key)
            Next
            Return inObject
        End Try
    End Function

    <Extension()>
    Public Function ValueOr(ByVal SourceObject As Object,
                       ByVal Key As Object,
                       Optional ByVal onnovalue As Boolean = False)
        Dim TossBool as Boolean = SourceObject.TryGetValue(Key, TossObj)
        If TossBool Then
            Return TossObj
        Else
            Return onnovalue
        End If
    End Function

    <Extension()>
    Public Function ValueOr(ByVal SourceObject As Object,
                       ByVal Key As Object,
                       ByVal onnovalue As Object)
        Dim TossBool as Boolean = SourceObject.TryGetValue(Key, TossObj)
        If TossBool Then
            Return TossObj
        Else
            Return onnovalue
        End If
    End Function
End Module

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-06-24
    • 1970-01-01
    • 2019-11-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-08
    • 1970-01-01
    相关资源
    最近更新 更多