Exception.Data 属性

定义

获取键/值对的集合,这些键/值对提供有关该异常的其他用户定义信息。

public:
 virtual property System::Collections::IDictionary ^ Data { System::Collections::IDictionary ^ get(); };
public virtual System.Collections.IDictionary Data { get; }
member this.Data : System.Collections.IDictionary
Public Overridable ReadOnly Property Data As IDictionary

属性值

IDictionary

一个对象,它实现 IDictionary 接口并包含用户定义的键/值对的集合。 默认值为空集合。

示例

以下示例演示如何使用 Data 属性添加和检索信息。

using namespace System;
using namespace System::Collections;

void NestedRunTest( bool displayDetails ); // forward declarations
void NestedRoutine1( bool displayDetails );
void NestedRoutine2( bool displayDetails );
void RunTest( bool displayDetails );

int main()
{
   Console::WriteLine("\nException with some extra information..." );
   RunTest(false);
   Console::WriteLine("\nException with all extra information..." );
   RunTest(true);
}

void RunTest( bool displayDetails )
{
   try
   {
      NestedRoutine1( displayDetails );
   }
   catch ( Exception^ e ) 
   {
      Console::WriteLine( "An exception was thrown." );
      Console::WriteLine( e->Message );
      if ( e->Data != nullptr )
      {
         Console::WriteLine( "  Extra details:" );

         for each (DictionaryEntry de in e->Data)
            Console::WriteLine("    Key: {0,-20}      Value: {1}", 
                               "'" + de.Key->ToString() + "'", de.Value);
      }
   }
}

void NestedRoutine1( bool displayDetails )
{
   try
   {
      NestedRoutine2( displayDetails );
   }
   catch ( Exception^ e ) 
   {
      e->Data[ "ExtraInfo" ] = "Information from NestedRoutine1.";
      e->Data->Add( "MoreExtraInfo", "More information from NestedRoutine1." );
      throw;
   }
}

void NestedRoutine2( bool displayDetails )
{
   Exception^ e = gcnew Exception( "This statement is the original exception message." );
   if ( displayDetails )
   {
      String^ s = "Information from NestedRoutine2.";
      int i = -903;
      DateTime dt = DateTime::Now;
      e->Data->Add( "stringInfo", s );
      e->Data[ "IntInfo" ] = i;
      e->Data[ "DateTimeInfo" ] = dt;
   }

   throw e;
}

/*
This example produces the following results:

Exception with some extra information...
An exception was thrown.
This statement is the original exception message.
  Extra details:
    The key is 'ExtraInfo' and the value is: Information from NestedRoutine1.
    The key is 'MoreExtraInfo' and the value is: More information from NestedRoutine1.

Exception with all extra information...
An exception was thrown.
This statement is the original exception message.
  Extra details:
    The key is 'stringInfo' and the value is: Information from NestedRoutine2.
    The key is 'IntInfo' and the value is: -903
    The key is 'DateTimeInfo' and the value is: 11/26/2002 2:12:58 PM
    The key is 'ExtraInfo' and the value is: Information from NestedRoutine1.
    The key is 'MoreExtraInfo' and the value is: More information from NestedRoutine1.
*/
// This example demonstrates the Exception.Data property.
using System;
using System.Collections;

class Sample
{
   public static void Main()
   {
      Console.WriteLine("\nException with some extra information...");
      RunTest(false);
      Console.WriteLine("\nException with all extra information...");
      RunTest(true);
   }

   public static void RunTest(bool displayDetails)
   {
      try {
         NestedRoutine1(displayDetails);
      }
      catch (Exception e) {
         Console.WriteLine("An exception was thrown.");
         Console.WriteLine(e.Message);
         if (e.Data.Count > 0) {
            Console.WriteLine("  Extra details:");
            foreach (DictionaryEntry de in e.Data)
               Console.WriteLine("    Key: {0,-20}      Value: {1}",
                                 "'" + de.Key.ToString() + "'", de.Value);
         }
      }
   }

   public static void NestedRoutine1(bool displayDetails)
   {
      try {
         NestedRoutine2(displayDetails);
      }
      catch (Exception e) {
         e.Data["ExtraInfo"] = "Information from NestedRoutine1.";
         e.Data.Add("MoreExtraInfo", "More information from NestedRoutine1.");
         throw;
      }
   }

   public static void NestedRoutine2(bool displayDetails)
   {
      Exception e = new Exception("This statement is the original exception message.");
      if (displayDetails) {
         string s = "Information from NestedRoutine2.";
         int i = -903;
         DateTime dt = DateTime.Now;
         e.Data.Add("stringInfo", s);
         e.Data["IntInfo"] = i;
         e.Data["DateTimeInfo"] = dt;
      }
      throw e;
   }
}
// The example displays the following output:
//    Exception with some extra information...
//    An exception was thrown.
//    This statement is the original exception message.
//      Extra details:
//        Key: 'ExtraInfo'               Value: Information from NestedRoutine1.
//        Key: 'MoreExtraInfo'           Value: More information from NestedRoutine1.
//
//    Exception with all extra information...
//    An exception was thrown.
//    This statement is the original exception message.
//      Extra details:
//        Key: 'stringInfo'              Value: Information from NestedRoutine2.
//        Key: 'IntInfo'                 Value: -903
//        Key: 'DateTimeInfo'            Value: 7/29/2013 10:50:13 AM
//        Key: 'ExtraInfo'               Value: Information from NestedRoutine1.
//        Key: 'MoreExtraInfo'           Value: More information from NestedRoutine1.
// This example demonstrates the Exception.Data property.
open System
open System.Collections

let nestedRoutine2 displayDetails =
    let e = Exception "This statement is the original exception message."
    if displayDetails then
        let s = "Information from nestedRoutine2."
        let i = -903
        let dt = DateTime.Now
        e.Data.Add("stringInfo", s)
        e.Data["IntInfo"] <- i
        e.Data["DateTimeInfo"] <- dt
    raise e

let nestedRoutine1 displayDetails =
    try
        nestedRoutine2 displayDetails
    with e ->
        e.Data["ExtraInfo"] <- "Information from nestedRoutine1."
        e.Data.Add("MoreExtraInfo", "More information from nestedRoutine1.")
        reraise ()

let runTest displayDetails =
    try
        nestedRoutine1 displayDetails
    with e ->
        printfn "An exception was thrown."
        printfn $"{e.Message}"
        if e.Data.Count > 0 then
            printfn "  Extra details:"
            for de in e.Data do
                let de = de :?> DictionaryEntry
                printfn $"""    Key: {"'" + de.Key.ToString() + "'",-20}      Value: {de.Value}"""

printfn "\nException with some extra information..."
runTest false
printfn "\nException with all extra information..."
runTest true

   
// The example displays the following output:
//    Exception with some extra information...
//    An exception was thrown.
//    This statement is the original exception message.
//      Extra details:
//        Key: 'ExtraInfo'               Value: Information from NestedRoutine1.
//        Key: 'MoreExtraInfo'           Value: More information from NestedRoutine1.
//
//    Exception with all extra information...
//    An exception was thrown.
//    This statement is the original exception message.
//      Extra details:
//        Key: 'stringInfo'              Value: Information from NestedRoutine2.
//        Key: 'IntInfo'                 Value: -903
//        Key: 'DateTimeInfo'            Value: 7/29/2013 10:50:13 AM
//        Key: 'ExtraInfo'               Value: Information from NestedRoutine1.
//        Key: 'MoreExtraInfo'           Value: More information from NestedRoutine1.
Imports System.Collections

Module Example
   Public Sub Main()
      Console.WriteLine()
      Console.WriteLine("Exception with some extra information...")
      RunTest(False)
      Console.WriteLine()
      Console.WriteLine("Exception with all extra information...")
      RunTest(True)
   End Sub

   Public Sub RunTest(displayDetails As Boolean)
      Try
         NestedRoutine1(displayDetails)
      Catch e As Exception
         Console.WriteLine("An exception was thrown.")
         Console.WriteLine(e.Message)
         If e.Data.Count > 0 Then
            Console.WriteLine("  Extra details:")
            For Each de As DictionaryEntry In e.Data
               Console.WriteLine("    Key: {0,-20}      Value: {1}",
                                 "'" + de.Key.ToString() + "'", de.Value)
            Next
         End If 
      End Try 
   End Sub 

   Public Sub NestedRoutine1(displayDetails As Boolean)
      Try
         NestedRoutine2(displayDetails)
      Catch e As Exception
         e.Data("ExtraInfo") = "Information from NestedRoutine1."
         e.Data.Add("MoreExtraInfo", "More information from NestedRoutine1.")
         Throw e
      End Try 
   End Sub

   Public Sub NestedRoutine2(displayDetails As Boolean)
      Dim e As New Exception("This statement is the original exception message.")
      If displayDetails Then 
         Dim s As String = "Information from NestedRoutine2." 
         Dim i As Integer = -903
         Dim dt As DateTime = DateTime.Now
         e.Data.Add("stringInfo", s)
         e.Data("IntInfo") = i
         e.Data("DateTimeInfo") = dt
      End If 
      Throw e
   End Sub 
End Module
' This example displays the following output: 
'    Exception with some extra information...
'    An exception was thrown.
'    This statement is the original exception message.
'      Extra details:
'        Key: 'ExtraInfo'               Value: Information from NestedRoutine1.
'        Key: 'MoreExtraInfo'           Value: More information from NestedRoutine1.
'    
'    Exception with all extra information...
'    An exception was thrown.
'    This statement is the original exception message.
'      Extra details:
'        Key: 'stringInfo'              Value: Information from NestedRoutine2.
'        Key: 'IntInfo'                 Value: -903
'        Key: 'DateTimeInfo'            Value: 7/29/2013 10:50:13 AM
'        Key: 'ExtraInfo'               Value: Information from NestedRoutine1.
'        Key: 'MoreExtraInfo'           Value: More information from NestedRoutine1.

注解

System.Collections.IDictionary使用属性返回Data的对象来存储和检索与异常相关的补充信息。 信息采用任意数量的用户定义的键/值对的形式。 每个键/值对的关键组件通常是一个标识字符串,而对的值组件可以是任何类型的对象。

键/值对安全性

属性返回的集合中存储的 Data 键/值对不安全。 如果应用程序调用嵌套的一系列例程,并且每个例程都包含异常处理程序,则生成的调用堆栈包含这些异常处理程序的层次结构。 如果较低级别的例程引发异常,则调用堆栈层次结构中的任何上层异常处理程序都可以读取和/或修改任何其他异常处理程序存储在集合中的键/值对。 这意味着必须确保密钥/值对中的信息不是机密的,如果键/值对中的信息损坏,应用程序将正常运行。

关键冲突

当不同的异常处理程序指定用于访问键/值对的相同键时,会发生键冲突。 开发应用程序时请谨慎,因为关键冲突的后果是,较低级别的异常处理程序可能会无意中与更高级别的异常处理程序通信,并且此通信可能会导致细微的程序错误。 但是,如果你谨慎,则可以使用关键冲突来增强应用程序。

避免密钥冲突

通过采用命名约定为键/值对生成唯一键来避免密钥冲突。 例如,命名约定可能会生成由应用程序句点分隔名称组成的密钥、为对提供补充信息的方法以及唯一标识符。

假设两个名为 Products 和 Suppliers 的应用程序,每个应用程序都有一个名为 Sales 的方法。 产品应用程序中的 Sales 方法 (产品库存单位或 SKU) 提供标识号。 供应商应用程序中的 Sales 方法提供供应商的标识号或 SID。 因此,此示例的命名约定将生成密钥“Products.Sales.SKU”和“Suppliers.Sales.SID”。

利用密钥冲突

通过使用存在一个或多个特殊的预排键来控制处理,利用密钥冲突。 假设在一种情况下,调用堆栈层次结构中的最高级别异常处理程序会捕获较低级别异常处理程序引发的所有异常。 如果存在具有特殊键的键/值对,则高级异常处理程序以某种非标准方式设置对象中 IDictionary 剩余键/值对的格式;否则,其余键/值对的格式采用某种正常方式。

现在假设在另一种情况下,调用堆栈层次结构的每个级别的异常处理程序捕获下一个较低级别异常处理程序引发的异常。 此外,每个异常处理程序都知道属性返回的 Data 集合包含一组键/值对,这些对可通过预先排列的键集访问。

每个异常处理程序都使用预先排列的键集来更新相应键/值对的值组件,其中包含该异常处理程序唯一的信息。 更新过程完成后,异常处理程序会将异常引发到下一个更高级别的异常处理程序。 最后,最高级别的异常处理程序访问键/值对,并显示来自所有较低级别异常处理程序的合并更新信息。

适用于

另请参阅