哈希表键取决于函数的定义位置



我遇到了powershell代码中最奇怪的问题。

我有两个文件,A.ps1和B.ps1。B包含非常简单的代码,它将环境映射到一周中的几天,然后使用当前环境来获得正确的几天:

$LocationA.ps1 # import Detect-Environment
$currentEnv = Detect-Environment
# 0 as Sunday, 6 as Saturday
$activatedEnvsAndWeekdays = @{
[CurrentEnv]::LOCAL = @(0, 1, 2, 3, 4, 5, 6)
[CurrentEnv]::DEV   = @(0, 1, 2, 3, 4, 5, 6)
[CurrentEnv]::UAT   = @()
[CurrentEnv]::PROD  = @(1)
}
$activatedWeekdayNums = $activatedEnvsAndWeekdays[$currentEnv]

A.ps1包含:

enum CurrentEnv {
LOCAL
DEV
UAT
PROD
}
function Detect-CinchyEnvironment {
$hostName = [System.Net.Dns]::GetHostName()
switch -Wildcard ($hostName) {
'*CINCHYPRD*' { [CurrentEnv]::PROD }
'*CINCHYUAT*' { [CurrentEnv]::UAT }
'*CINCHYDEV*' { [CurrentEnv]::DEV }
Default { [CurrentEnv]::LOCAL }
}
}

由于我当前的env是[CurrentEnv]::LOCAL,所以$activatedWeekdayNums应该是列表@(0, 1, 2, 3, 4, 5, 6)。但事实并非如此!是$null。经过大量挖掘,我发现了原因。

当我在文件中定义并调用Detect-Environment时,代码运行良好。但是,当我在另一个名为A.ps1的文件中定义Detect-Environment,然后用. $LocationA.ps1导入它时,它不起作用,即使$currentEnv说它等于[CurrentEnv]::LOCAL。事实上,如果我比较通过将$currentEnv1(局部函数(与$currentEnv2(导入函数(相等而获得的变量,则$currentEnv2 -eq $currentEnv返回True。但与CCD_ 14的结果不同。完全困惑。

感谢您的帮助!很乐意提供更多上下文/代码。

编辑:$currentEnv1.GetType()等于:

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     CurrentEnv                               System.Enum

$currentEnv2.GetType()等于相同的东西:

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     CurrentEnv                               System.Enum

第2版:为了添加更多信息,即使我使用$activatedEnvsAndWeekdays[[CurrentCinchyEnv]::LOCAL](因此我根本不使用$currentEnv(,在导入Detect-Environmentenum CurrentCinchyEnv时也不会返回任何信息。

按照评论中的要求发布此答案。对于想知道如何重现这个错误(?(的人来说,这里有一个可重现的最小示例。

  • script1.ps1
enum TestEnum {
Test
}
$key = . .script2.ps1
$map = @{ [TestEnum]::Test = 'hello' }
$map[$key]
  • script2.ps1
[TestEnum]::Test

如果我们试图在干净的PS会话中运行script1.ps1,我们应该得到正确的值hello。但是,任何后续对script1.ps1的更新(必须是定义enum.ps1(都将导致PowerShell发出一个同名的新类型:

PS /> [AppDomain]::CurrentDomain.GetAssemblies().GetTypes() |
Where-Object Name -EQ TestEnum
IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     TestEnum                                 System.Enum
True     True     TestEnum                                 System.Enum

还有一个更新的组装版本:

PS /> [AppDomain]::CurrentDomain.GetAssemblies().GetTypes() |
Where-Object Name -EQ TestEnum | ForEach-Object AssemblyQualifiedName
TestEnum, PowerShell Class Assembly, Version=1.0.0.2, Culture=neutral, PublicKeyToken=null
TestEnum, PowerShell Class Assembly, Version=1.0.0.3, Culture=neutral, PublicKeyToken=null

值得注意的是,这只会在处理代码时影响我们,但错误不应在干净的会话中重现,换句话说,如果您希望在hashtable上使用引用类型密钥,并且可以忍受每次更新代码时都必须重新启动PowerShell会话,那么在运行时应该可以。

作为个人建议,我会使用字符串作为哈希表键来避免这种情况

作为解决方法,转换类型应在不需要重新启动会话的情况下解决问题:

$map[[TestEnum] $keyEnum]

最新更新