【问题标题】:Why is this try/catch block magically swallowing the exception?为什么这个 try/catch 块神奇地吞下了异常?
【发布时间】:2016-02-07 02:20:20
【问题描述】:

我正在编写一个 PowerShell 脚本,它使用反射 API 来获取程序集中的所有命名空间。无论如何,这无关紧要。以下是代码的相关部分:

function Get-Namespaces($assembly)
{
    $assemblyClass = [Reflection.Assembly]
    $assemblyObject = $assemblyClass::ReflectionOnlyLoadFrom($assembly)
    $types = $assemblyObject.GetTypes() # This is the part that's having issues
    return $types | ? IsPublic | select Namespace -Unique
}

cd $PSScriptRoot

$assemblies = @()
$assemblies += Get-WpfAssemblies
$assemblies += Get-UwpAssembly

$namespaces = $assemblies | % {
    % { Get-Namespaces $_ }
}

由于某种原因,初始化$types 的部分似乎有问题;具体来说,它告诉我捕获异常并检查捕获的异常的LoaderExceptions 属性以获取更多信息。所以当我尝试这样做时:

try { $assemblyObject.GetTypes() } catch { echo $_.LoaderExceptions }

运行它,脚本什么也不打印。

为什么会发生这种情况,我该如何解决?


对于想要完整试用该脚本的人,我已经公开了GitHub gist.(请注意,它仅在您安装了 Windows 10 开发工具的情况下才有效,但我确信合理有经验的 PowerShell 用户可以修改脚本以在他们的机器上运行。)

【问题讨论】:

  • try 只会捕获终止错误,因此您的 catch 块可能没有被执行。当您只有 $assemblyObject.GetTypes() 时,控制台中会显示什么
  • @Matt 此消息:Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information.
  • 我不认为这会被填充,但您是否在此处看到您的错误:$error。这是一个包含所有最近错误的自动变量。 $error[0] 应该是最后一个错误。请注意,它包含您会话中的所有错误。
  • $_ 在 catch 块中是 System.Management.Automation.ErrorRecord。它没有属性LoaderExceptions。因此,非严格模式下的echo 为空。是这样吗?
  • $_.Exception.InnerException.LoaderExceptions

标签: windows powershell error-handling scripting


【解决方案1】:

不幸的是,我没有在 Windows PC 上尝试这个,但是通过一些谷歌搜索,看起来正确的语法应该是:

try {
    ....
} catch [System.Reflection.ReflectionTypeLoadException] {
    echo $_.LoaderExceptions
}

查看http://www.vexasoft.com/blogs/powershell/7255220-powershell-tutorial-try-catch-finally-and-error-handling-in-powershell。似乎有一些关于 PowerShell 中异常处理的好信息。

【讨论】:

    【解决方案2】:

    您捕获的(最上面的)异常可能是ErrorRecord,它没有属性LoaderExceptions。 PowerShell 将缺少的属性扩展为 $null 值,这些值将转换为空字符串以进行输出。您可以通过使用 Get-Member cmdlet 检查 catch 块中的当前对象来检查异常类型及其属性和方法:

    try { $assemblyObject.GetTypes() } catch { Get-Member -InputObject $_ }
    

    由于 PowerShell 倾向于将相关信息隐藏在嵌套异常中,您可能需要执行以下操作来展开它们:

    try {
      ...
    } catch {
      $_.InvocationInfo.Line.Trim() + "`n"
      $_.InvocationInfo.PositionMessage + "`n"
    
      $e = $_.Exception
      do {
        $e.Message
        if ($e.LoaderExceptions) { $e.LoaderExceptions }
        $e = $e.InnerException
      } while ($e)
    }
    

    【讨论】:

      【解决方案3】:

      问题在于 PowerShell 将回显的内容解释为返回值:

      function Generate-ErrorMessage
      {
          try
          {
              blah
          }
          catch
          {
              echo $_
          }
      }
      
      $message = Generate-ErrorMessage # Will contain some PowerShell message about not being able to find 'blah'
      

      解决办法是直接使用Console.WriteLine

      function Generate-ErrorMessage
      {
          try
          {
              blah
          }
          catch
          {
              [Console]::WriteLine($_)
          }
      }
      
      Generate-ErrorMessage # prints the message to the console
      

      没有那么漂亮,但可以按预期工作。


      编辑: Write-Host 也有效:

      try { blah }
      catch { Write-Host $_ }
      

      其他命令可以看here.


      编辑 2: 事实上,Out-Host 更适合记录:

      try { blah }
      catch { $_ | gm | Out-Host } # displays more detailed info than Write-Host
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-11-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-05-13
        • 2010-09-07
        • 1970-01-01
        • 2011-09-23
        相关资源
        最近更新 更多