转换字典<tkey,list <tvalue =“”>&gt; to ReadOnlyDictionary <tkey,readonlycollection <tvalue =“”>&gt;

时间:2016-03-01 21:44:08

标签: c# .net dictionary readonly-collection

我有一本字典如下:

public enum Role { Role1, Role2, Role3, }
public enum Action { Action1, Action2, Action3, }

var dictionary = new Dictionary<Role, List<Action>>();

dictionary.Add(RoleType.Role1, new Action [] { Action.Action1, Action.Action2 }.ToList());

现在我希望能够构建一个只读字典,其值类型也是只读的,如下所示:

var readOnlyDictionary = new ReadOnlyDictionary<Role, ReadOnlyCollection<Action>>(dictionary);

由于TValue类型的差异,最后一行显然会导致编译时错误。

使用List<TValue>也是必要的,因为原始字典是以编程方式从外部源填充的。

有没有简单的方法来执行此转换?

2 个答案:

答案 0 :(得分:8)

一种可能性(对于大型集合可能不是最理想的)是构造所需类型的新Dictionary对象(使用Enumerable.ToDictionary overload)并使用List.AsReadOnly() extension这样:

var readOnlyDictionary = 
    new ReadOnlyDictionary<Role, ReadOnlyCollection<Action>>
        (dictionary.ToDictionary(k => k.Key, v => v.Value.AsReadOnly()));

答案 1 :(得分:1)

将近 5 年之后,这里有一个简单的解决方案,它可以适应字典,正确处理值类型的协方差。

Option Explicit

Sub lookupClientEmails()
    
    ' Source
    Const sName As String = "Orders"
    Const sFirstRow As Long = 2
    Const sLookup As String = "C" ' 3
    Const sResultOffset As Long = 1 ' referring to column 'D'
    ' Destination
    Const dName As String = "Clients"
    Const dFirstRow As Long = 2
    Const dLookup As String = "M" ' 13
    Const dResult As String = "V" ' 22
    ' Workbook
    Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
    ' Source
    Dim sws As Worksheet: Set sws = wb.Worksheets(sName)
    Dim sLastRow As Long
    sLastRow = sws.Cells(sws.Rows.Count, sLookup).End(xlUp).Row
    Dim srg As Range
    Set srg = sws.Cells(sFirstRow, sLookup).Resize(sLastRow - sFirstRow + 1)
    ' Destination
    Dim dws As Worksheet: Set dws = wb.Worksheets(dName)
    Dim dLastRow As Long
    dLastRow = dws.Cells(dws.Rows.Count, dLookup).End(xlUp).Row
    ' Variables
    Dim sCell As Range
    Dim i As Long
    Dim FirstAddress As String
    ' Loop
    For i = dFirstRow To dLastRow
        Set sCell = srg.Find(dws.Cells(i, dLookup).Value, _
            srg.Cells(srg.Rows.Count), xlFormulas, xlWhole)
        If Not sCell Is Nothing Then
            FirstAddress = sCell.Address
            Do
                If sCell.Offset(, sResultOffset).Value <> "" Then
                    dws.Cells(i, dResult).Value _
                        = sCell.Offset(, sResultOffset).Value
                    Exit Do
                End If
                Set sCell = srg.FindNext(sCell)
            Loop While sCell.Address <> FirstAddress
        End If
    Next i

End Sub