【问题标题】:Customize .NET framework generated exception messages?自定义 .NET 框架生成的异常消息?
【发布时间】:2011-06-02 15:17:57
【问题描述】:

我想知道是否有一种合理的方法可以自定义 .NET 框架引发的异常消息?下面是我经常写的一段代码,在很多不同的场景中,以达到为我的用户提供合理的异常信息的效果。

public string GetMetadata(string metaDataKey)
{
  // As you can see, I am doing what the dictionary itself will normally do, but my exception message has some context, and is therefore more descriptive of the actual problem.
  if (!_Metadata.ContainsKey(metaDataKey))
  {
    throw new KeyNotFoundException(string.Format("There is no metadata that contains the key '{0}'!", metaDataKey));
  }

  // This will throw a 'KeyNotFoundException' in normal cases, which I want, but the message "The key is not present in the dictionary" is not very informative.  This is the exception who's message I wish to alter.
  string val = _Metadata[metaDataKey].TrimEnd();
  return val;
}

如您所见,我实际上是在生成重复的代码,只是为了使用不同的(更好的)消息。

编辑:
我正在寻找的,基本上是这样的:

KeyNotFoundException.SetMessage("this is my custom message!")
{
// OK, now this will send off the message I want when the exception appears!
// Now I can avoid all of that silly boilerplate!
string val = _Metadata[metaDataKey].TrimEnd();
}

无论如何,我认为不存在这样的功能,但如果存在,我确实会非常高兴。以前有没有人解决过这类问题?看起来我最终需要某种类型的扩展方法......

【问题讨论】:

    标签: c# .net exception exception-handling customization


    【解决方案1】:

    除非我在您的问题中遗漏了什么,否则这正是您应该做的。我很确定每个异常都包含一个将string message 作为参数的重载。如果您想提供超出 .NET 提供的“默认”的信息,则需要设置特定的消息。

    【讨论】:

    • 我想每个人都错过了这个问题。我知道当我尝试访问字典时会出现“KeyNotFound”。我只想更改那个例外的包含消息。我发现自己进行检查或捕获原始异常并不是很有用。
    【解决方案2】:

    您似乎一开始就以正确的方式做这件事。但是,我会改变您检查异常的方式:

    public string GetMetadata(string metaDataKey)
    {
        try
        {
            string val = _Metadata[metaDataKey].TrimEnd();
            return val;
        }
        catch (KeyNotFoundException ex)
        {
            // or your own custom MetaDataNotFoundException or some such, ie:
            // throw new MetaDataNotFoundException(metaDatakey);
            throw new KeyNotFoundException(string.Format("There is no metadata that contains the key '{0}'!", metaDataKey));
        }
    }
    

    【讨论】:

    • 这样你会丢失部分堆栈轨道。我会将原始异常作为 InnerException 添加到您要抛出的异常中。
    • @whatknott 绝对。我写得很简洁,但你是对的。
    • 为什么这比我原来的方法更好?还是只是语法不同,因为?
    • 这主要是风格问题并且是主观的,但我发现 try/catch 有助于分离逻辑并且错误处理是一种很好且易于管理的方式。我会改变你已经抛出异常的方式的唯一原因是如果你想本地化文本,因为你可以让你的自定义异常处理程序选择正确的文本字符串来使用。
    【解决方案3】:

    只需从KeyNotFoundException 类继承并覆盖 Message 属性以生成更有意义的消息,然后使用您自己的异常类和适当的构造函数。这正是继承的意义所在,增加了价值。即

    throw new MetaDataKeyNotFoundException(string metaDataKey);
    

    【讨论】:

    • 但是看看他的问题。继承不能帮助他实现他想要的,真的。他已经通过用自己的消息文本抛出自己的异常来“覆盖”消息。
    • 当他可以在他抛出的异常的构造函数中提供正确的消息时,为什么要这么麻烦呢?任何可能引发异常的*代码都应该包含在try/catch 中(*- 对于给定的“any”值)。
    • 嗯,它可以像throw new MetaDataKeyNotFoundException(string metaDataKey); 这样更简洁。
    • 我不喜欢多次输入相同的文本...... id 继承了它,并提供了一个自定义构造函数,以便它用你想要的内容填充消息。这样,您也可以将字符串移动到资源文件中。克里斯沃尔什也提出了一个很好的观点。人们对继承异常和提供自定义异常是否正确有非常强烈的感觉。
    【解决方案4】:

    Exception 类已经支持通过使用属性Exception.Data 添加与发生错误的特定事件或场景相关联的自定义用户数据。

    来自该属性的 MSDN 条目,重点是我的:

    获取提供用户定义的其他信息关于异常的键/值对集合。

    我知道您希望覆盖 Message 属性,但使用 Data 您可以通过确保异常处理程序知道如何处理这些额外数据来实现同样的目的。

    【讨论】:

    • 是的,但我试图避免额外的 try / catch 块。不过,这对于其他场景来说是一个很好的方法......
    【解决方案5】:

    异常是对象。与大多数对象一样,您无法控制创建者创建对象的方式,无论创建者是否为 .NET Framework。

    您如何告诉 .NET Framework 在什么情况下创建什么消息?在您发布的情况下,您可能希望在 KeyNotFoundException 上发送一条消息,而在不同的情况下再发送一条消息。你如何区分这两种情况?

    【讨论】:

      【解决方案6】:

      KeyNotFoundException.SetMessage("这个 是我的自定义消息!");

      没有这样的功能(除了可能会弄乱内部或资源)。但是无论如何它应该如何工作。您将为使用异常的每段代码更改消息 - 其中一些您的新消息根本没有意义。

      考虑任意使用Dictionary 类,甚至是一些完全不同的代码,遵循重用现有异常类型的“最佳实践”,所有这些都会突然使用您的(非常)自定义错误消息。

      【讨论】:

      • 是的,就像我说的,我认为不存在这样的功能。当然,如果确实如此,我希望没有人会愚蠢到实现它以提供您所描述的行为。
      【解决方案7】:

      这是我想出的一个解决方案,但我想指出,它更像是一个补丁而不是任何东西。它确实有效,但可能并不适合所有应用程序。我什至想不出一个好名字。

        public class ContextDictionary<TKey, TValue> : Dictionary<TKey, TValue>
        {
          public TValue this[TKey key, string context]
          {
            get
            {
              if (!this.ContainsKey(key))
              {
                throw new KeyNotFoundException(string.Format("There is no {0} that contains the key '{1}'!", context, key));
              }
              return this[key];
            }
            set { this[key] = value; }
          }
        }
      

      所以现在我可以这样说,并获得我真正想要的更具描述性的异常消息。

      var _MetaData = new ContextDictionary<string,string>();
      string val = _Metadata[metaDataKey, "metadata"].TrimEnd();
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-11-04
        • 2012-01-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多