【问题标题】:Less try-catch statements?更少的 try-catch 语句?
【发布时间】:2014-05-06 06:12:16
【问题描述】:

我有点沮丧,试图找出在 C# 中使用 try-catch 语句处理异常的最佳途径是什么。我想要代码,所以如果在尝试打开注册表项时抛出异常,那么它将继续到下一个注册表项。我能想到的唯一方法是将每个函数调用封装在一个 try-catch 语句中,但对我来说,这样做似乎还有很长的路要走。

  • 还有其他方法可以做到这一点吗?
  • 您能否将所有代码包含在单个 try-catch 语句中,并且当发生异常时,是否将其移至下一行代码(如跳过)?
  • 我知道这可能是否定的,但是如果在参数中设置了变量,可以使用ScanSubKey 函数来检查异常吗?

没有 try-catch 语句

ScanSubKey(Registry.ClassesRoot);
ScanSubKey(Registry.LocalMachine.OpenSubKey("SOFTWARE"));
ScanSubKey(Registry.CurrentUser.OpenSubKey("SOFTWARE"));
if (Is64BitOS)
{
    ScanSubKey(Registry.ClassesRoot.OpenSubKey("Wow6432Node"));
    ScanSubKey(Registry.LocalMachine.OpenSubKey("SOFTWARE\\Wow6432Node"));
    ScanSubKey(Registry.CurrentUser.OpenSubKey("SOFTWARE\\Wow6432Node"));
}

示例

try {
    ScanSubKey(Registry.ClassesRoot);
} 
catch (Exception ex) {
    Debug.WriteLine("The following error occurred opening a registry key: " + ex.Message);
}
try {
    ScanSubKey(Registry.LocalMachine.OpenSubKey("SOFTWARE"));
} 
catch (Exception ex) {
    Debug.WriteLine("The following error occurred opening a registry key: " + ex.Message);
}
try {
    ScanSubKey(Registry.CurrentUser.OpenSubKey("SOFTWARE"));
} 
catch (Exception ex) {
    Debug.WriteLine("The following error occurred opening a registry key: " + ex.Message);
}

if (Is64BitOS)
{
    try {
        ScanSubKey(Registry.ClassesRoot.OpenSubKey("Wow6432Node"));
    } 
    catch (Exception ex) {
        Debug.WriteLine("The following error occurred opening a registry key: " + ex.Message);
    }
    try {
        ScanSubKey(Registry.LocalMachine.OpenSubKey("SOFTWARE\\Wow6432Node"));
    } 
    catch (Exception ex) {
        Debug.WriteLine("The following error occurred opening a registry key: " + ex.Message);
    }
    try {
        ScanSubKey(Registry.CurrentUser.OpenSubKey("SOFTWARE\\Wow6432Node"));
    } 
    catch (Exception ex) {
        Debug.WriteLine("The following error occurred opening a registry key: " + ex.Message);
    }
}

【问题讨论】:

  • AFAIK 这是不可能的,请参阅here

标签: c# windows optimization registry try-catch


【解决方案1】:

创建一个新方法TryScanSubKey。然后你的代码又看起来干净了:

TryScanSubKey(Registry.ClassesRoot);
TryScanSubKey(Registry.LocalMachine.OpenSubKey("SOFTWARE"));
TryScanSubKey(Registry.CurrentUser.OpenSubKey("SOFTWARE"));
if (Is64BitOS)
{
    TryScanSubKey(Registry.ClassesRoot.OpenSubKey("Wow6432Node"));
    TryScanSubKey(Registry.LocalMachine.OpenSubKey("SOFTWARE\\Wow6432Node"));
    TryScanSubKey(Registry.CurrentUser.OpenSubKey("SOFTWARE\\Wow6432Node"));
}

TryScanSubKey 的实现应该很明显,但为了完整起见,这里是:

void TryScanSubKey(RegistryKey key)
{
    try
    {
        ScanSubKey(key);
    } 
    catch (Exception ex)
    {
        Debug.WriteLine("The following error occurred opening a registry key: " + ex.Message);
    }
}

请注意,一般,吞下一个错误是不好的做法,吞下所有个错误更糟糕。所以请考虑(至少)用更具体的东西替换catch (Exception ex),例如catch (TheSpecificExceptionThrownByScanSubKey ex).

【讨论】:

  • 如果在发送到TryScanSubKey之前无法打开注册表项,那么如果抛出异常,这是否仍会导致程序失败?
  • @ub3rst4r: RegistryKey.OpenSubKey 不会在密钥丢失时抛出异常——它只是返回 null,可以在 TryScanSubKey 中轻松检查。如果操作由于其他原因而失败,则程序应该失败,因为在这种情况下,注册表中的某些内容已严重损坏。
  • 如果是由于对子键的权限呢?
  • @ub3rst4r:然后抛出 SecurityException。我认为这是一件好事,因为普通用户应该拥有对 HKCU、HKLM\Software 和 HKCU\Software(以及 WOW64 对应项)的读取权限。如果访问被拒绝,则说明有问题。
【解决方案2】:

也许这会是一个更好的方法:

public bool TryOpenRegKey(RegistryKey regKey, string subKey = default(string))
{
  try
  {
    if (string.IsNullOrWhiteSpace(subKey))
      ScanSubKey(regKey);
    else
      ScanSubKey(regKey.OpenSubKey(subKey));

    return true;
  }
  catch(Exception ex)
  {
    Debug.WriteLine("The following error occurred opening a registry key: " + ex.Message);
    return false;
  }
}

然后:

TryOpenRegKey(Registry.ClassesRoot);
TryOpenRegKey(Registry.LocalMachine, "SOFTWARE");
TryOpenRegKey(Registry.CurrentUser, "SOFTWARE");

if (Is64BitOS)
{
  TryOpenRegKey(Registry.ClassesRoot, "Wow6432Node");
  TryOpenRegKey(Registry.LocalMachine, "SOFTWARE\\Wow6432Node");
  TryOpenRegKey(Registry.CurrentUser, "SOFTWARE\\Wow6432Node");
}

【讨论】:

    【解决方案3】:

    我称之为“执行者”:

        public static void Execute(Action action)
        {
            try
            {
                action();
            }
            catch (Exception ex)
            {
            }
        }
    

    然后使用它:

    Execute(() => ScanSubKey(Registry.ClassesRoot));
    

    【讨论】:

    • @Maarten 我不会争辩说这是一个很好的做法 - 但它可以完成工作!
    【解决方案4】:

    您是否考虑过在 ScanSubKey 函数本身内放置一个 try/catch 并在发生错误时返回?

    【讨论】:

      猜你喜欢
      • 2018-10-14
      • 2011-01-06
      • 1970-01-01
      • 1970-01-01
      • 2018-11-20
      • 1970-01-01
      • 2010-09-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多