【问题标题】:What's the difference between @{} and [Hashtable]::Clear()?@{} 和 [Hashtable]::Clear() 有什么区别?
【发布时间】:2013-08-06 19:43:06
【问题描述】:

全部!

我正在编写将标准 INI 文件结构转换为基于哈希表和数组的代码。例如下图的INI sn-p:

[Book]
title="Moby Dick"
author="Herman Melville"
genre=fiction
genre=fantasy

[Book]
title="James and the Giant Peach"
author="Roald Dahl"
genre="fiction"

看起来像:

@{
    "Book" = [
        @{
            "title" = ["Moby Dick"];
            "author" = ["Herman Melville"];
            "genre" = ["fiction","fantasy"]
        },
        @{
            "title" = ["James and the Giant Peach"];
            "author" = ["Roald Dahl"];
            "genre" = ["fiction"]
        }
    ]

}

我想说明具有多个同名节和具有多个同名属性的节的 INI 文件,因此是这种数据结构。我知道我可以使用一棵树来做同样的事情,但我不太关心它的速度,而且在我编写它的时候这更容易实现。

这是通过更新一个哈希表来完成的,该哈希表将一个部分中的所有属性与其值相关联(我们称之为$items),然后更新将每个部分与上述哈希表相关联的主哈希表(我们称之为$results )。哈希表是全局的,属性哈希表在迭代到新部分时会被清除。

虽然我编写的代码可以做到这一点并且运行良好,但几分钟后我对 Powershell 清除哈希表的方式感到困惑。如果我使用$items.Clear() 清除$items$results 中的所有元素关联的哈希表也会被清除。 但是,如果我通过声明$items=@{} “清除”它,则不会发生这种情况.

我假设发生这种情况是因为前一种情况下的哈希表都是对全局哈希表的引用,并且在后一种情况下是独立的对象。这是怎么回事?

代码如下;抱歉,如果其中任何一个令人困惑(并且它不是典型的 Powershell 语法)。将$items = @{} 替换为$items = $items.Clear() 进行复制:

function parse ($file) {
    $result = @{}
    if (!(Test-Path $file)) {   
        write-host "File does not exist: $file"
    } elseif (!($data = cat $file)) {
        write-host "File has no data: $file"
    } else {
        $last_value = ""
        $last_data = ""
        $items = @{}
        foreach ($line_raw in $data | ?{$_.Trim().Length -gt 0}) {
            $line = $line_raw.TrimStart().TrimEnd()
            $first_char = $line[0]
            switch ($first_char) {
                ';' { 
                    continue 
                }
                '[' {
                    $key = $line -replace "\[|\]",""
                    if ($last_key) {
                        if (!($result.ContainsKey($last_key)))
                            { $result.Add($last_key,@($items)) }
                        else
                            { $result[$last_key] += $items }
                        if ($last_key -ne $key) 
                            { $items = @{} }                    
                    }
                    $last_key = $key
                }
                default {
                    $item , $data = $(
                        $sep = $line.indexOf('=')
                        $line.substring(0,$sep) , $line.substring($sep+1)
                    )
                    if (!$items.ContainsKey($item))
                        { $items.Add($item,@($data))    }
                    else 
                        { $items[$item] += $data }
                }
            }
        }
        $result
    }
}

【问题讨论】:

  • 我似乎无法复制这种行为。您能否发布有关如何设置不同哈希表的代码?

标签: .net powershell


【解决方案1】:

$items 这样的变量指的是在这种情况下包含哈希表的存储位置。当您为变量分配 @{} 的值时,您正在为变量分配对新的空哈希表的引用。如果没有其他内容引用原始哈希表,垃圾收集器将回收其内存。对哈希表执行Clear() 方法会导致它重置为空状态。

【讨论】:

  • 是的,我想这就是正在发生的事情。再次感谢,基思!作为一个附带问题,这是使用 Powershell 解析 INI 文件的推荐方法吗?虽然 The Scripting Guys 上的示例使用了更简单的代码,但它似乎没有将属性与其值相关联,尽管它确实将部分与其属性相关联。提前致谢!
【解决方案2】:

首先,我认为您的意思是:$items.Clear() 而不是 $items = $items.Clear()

我得仔细看看,因为我还没有发现任何可疑之处,但我只是想让你知道,为了回答一个更基本的问题,上面的所有代码都在做你能做的事情当应用于内存中的哈希表和存储的文件时,使用 ConvertTo-Json 和 ConvertFrom-Json cmdlet 在 Powershell 中获取几行代码。试一试,你就会明白我的意思了。

【讨论】:

  • 谢谢!你是对的,我的意思是$items.Clear(). 这是否适用于这些数据的结构方式?我认为这包含在 Powershell v3+ 中。
  • 是的。看看它是如何相互转换哈希表的。我以为你可以使用 v3,因为我没有看到任何相反的东西。如果不是这种情况,您应该在问题中真正包含这种类型的约束。
猜你喜欢
  • 2012-04-27
  • 1970-01-01
  • 2011-08-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多