表示應用程序執行期間發生的錯誤。
public class Exception : System . Runtime . Serialization . ISerializable
繼承
| Object | Exception |
|---|
派生
System.Exception
1. 系統異常
├── 內存與資源異常
│ ├── System.OutOfMemoryException
│ ├── System.InsufficientMemoryException
│ ├── System.StackOverflowException
│ └── System.AccessViolationException
│
├── 類型系統異常
│ ├── System.InvalidCastException
│ ├── System.TypeLoadException
│ ├── System.TypeInitializationException
│ ├── System.TypeUnloadedException
│ ├── System.DllNotFoundException
│ └── System.EntryPointNotFoundException
│
├── 算術運算異常
│ ├── System.ArithmeticException
│ │ ├── System.DivideByZeroException
│ │ ├── System.OverflowException
│ │ └── System.NotFiniteNumberException
│ └── System.DataMisalignedException
│
├── 數組與集合異常
│ ├── System.IndexOutOfRangeException
│ ├── System.ArrayTypeMismatchException
│ ├── System.RankException
│ ├── System.Collections.Generic.KeyNotFoundException
│ └── System.InvalidOperationException
│
├── 空引用與對象異常
│ ├── System.NullReferenceException
│ ├── System.ObjectDisposedException
│ └── System.MissingMemberException
│
└── 程序狀態異常
├── System.InvalidProgramException
├── System.BadImageFormatException
├── System.ExecutionEngineException
└── System.AppDomainUnloadedException
2. 參數與驗證異常
├── 參數驗證異常
│ ├── System.ArgumentException
│ │ ├── System.ArgumentNullException
│ │ ├── System.ArgumentOutOfRangeException
│ │ └── System.DuplicateWaitObjectException
│ └── System.ComponentModel.DataAnnotations.ValidationException
│
├── 格式與解析異常
│ ├── System.FormatException
│ ├── System.Text.Json.JsonException
│ ├── System.Xml.XmlException
│ └── System.Formats.Asn1.AsnContentException
│
└── 操作不支持異常
├── System.NotImplementedException
├── System.NotSupportedException
├── System.PlatformNotSupportedException
└── System.MulticastNotSupportedException
3. I/O 與文件系統異常
├── 通用I/O異常
│ ├── System.IO.IOException
│ │ ├── System.IO.DirectoryNotFoundException
│ │ ├── System.IO.FileNotFoundException
│ │ ├── System.IO.FileLoadException
│ │ ├── System.IO.PathTooLongException
│ │ ├── System.IO.DriveNotFoundException
│ │ ├── System.IO.EndOfStreamException
│ │ └── System.IO.PipeException
│ └── System.UnauthorizedAccessException
│
├── 存儲相關異常
│ ├── System.IO.IsolatedStorage.IsolatedStorageException
│ ├── System.IO.Log.SequenceFullException
│ └── System.AddIn.Hosting.AddInSegmentDirectoryNotFoundException
│
└── 序列化異常
├── System.Runtime.Serialization.SerializationException
├── System.Runtime.Serialization.InvalidDataContractException
└── System.Workflow.ComponentModel.Serialization.WorkflowMarkupSerializationException
4.網絡與通信異常
├── HTTP與Web異常
│ ├── System.Net.WebException
│ ├── System.Net.Http.HttpRequestException
│ ├── System.Web.HttpException
│ └── System.ServiceModel.CommunicationException
│
├── 套接字與傳輸異常
│ ├── System.Net.Sockets.SocketException
│ ├── System.Net.Mail.SmtpException
│ └── System.Net.PeerToPeer.PeerToPeerException
│
└── 服務與遠程異常
├── System.ServiceModel.InvalidMessageContractException
├── System.ServiceModel.QuotaExceededException
└── System.Runtime.Remoting.MetadataServices.SUDSGeneratorException
5. 數據訪問異常
├── 數據庫通用異常
│ ├── System.Data.Common.DbException
│ │ ├── System.Data.SqlClient.SqlException
│ │ ├── System.Data.OleDb.OleDbException
│ │ ├── System.Data.Odbc.OdbcException
│ │ └── Microsoft.Data.SqlClient.SqlException
│ └── System.Data.Linq.ChangeConflictException
│
├── ORM框架異常
│ ├── Microsoft.EntityFrameworkCore.DbUpdateException
│ └── System.Data.Linq.ChangeConflictException
│
└── 目錄服務異常
├── System.DirectoryServices.ActiveDirectory.ActiveDirectoryObjectExistsException
├── System.DirectoryServices.ActiveDirectory.ActiveDirectoryObjectNotFoundException
└── System.DirectoryServices.Protocols.DirectoryException
6. 併發與異步異常
├── 線程與同步異常
│ ├── System.Threading.SynchronizationLockException
│ ├── System.Threading.ThreadStateException
│ ├── System.Threading.ThreadAbortException
│ ├── System.Threading.ThreadInterruptedException
│ ├── System.Threading.ThreadStartException
│ └── System.Threading.AbandonedMutexException
│
├── 任務與異步異常
│ ├── System.OperationCanceledException
│ │ └── System.Threading.Tasks.TaskCanceledException
│ ├── System.AggregateException
│ ├── System.Threading.Tasks.TaskSchedulerException
│ └── System.TimeoutException
│
└── 同步原語異常
├── System.Threading.SemaphoreFullException
├── System.Threading.WaitHandleCannotBeOpenedException
├── System.Threading.BarrierPostPhaseException
└── System.Threading.LockRecursionException
7. 安全與權限異常
├── 安全框架異常
│ ├── System.Security.SecurityException
│ ├── System.Security.VerificationException
│ ├── System.Security.Cryptography.CryptographicException
│ └── System.Security.Policy.PolicyException
│
├── 權限與訪問異常
│ ├── System.UnauthorizedAccessException
│ ├── System.Security.Principal.IdentityNotMappedException
│ └── System.Security.HostProtectionException
│
└── 認證與令牌異常
├── System.IdentityModel.Tokens.SecurityTokenException
└── System.Security.RightsManagement.RightsManagementException
8. 反射與元數據異常
├── 反射調用異常
│ ├── System.Reflection.TargetException
│ ├── System.Reflection.TargetInvocationException
│ ├── System.Reflection.TargetParameterCountException
│ └── System.Reflection.ReflectionTypeLoadException
│
├── 成員訪問異常
│ ├── System.MemberAccessException
│ ├── System.FieldAccessException
│ ├── System.MethodAccessException
│ └── System.TypeAccessException
│
└── 元數據異常
├── System.Reflection.Metadata.ImageFormatLimitationException
└── System.ComponentModel.Composition.CompositionException
9. 國際化與本地化異常
├── 本地化異常
│ ├── System.Resources.MissingManifestResourceException
│ ├── System.Resources.MissingSatelliteAssemblyException
│ └── System.Globalization.CultureNotFoundException
│
├── 時區異常
│ ├── System.TimeZoneNotFoundException
│ └── System.InvalidTimeZoneException
│
└── 編碼異常
├── System.Text.EncoderFallbackException
└── System.Text.DecoderFallbackException
10. 互操作異常
├── COM與ActiveX異常
│ ├── System.Runtime.InteropServices.COMException
│ ├── System.Runtime.InteropServices.ExternalException
│ ├── System.Runtime.InteropServices.InvalidComObjectException
│ ├── System.Windows.Forms.AxHost.InvalidActiveXStateException
│ └── System.Runtime.InteropServices.SEHException
│
├── 互操作支持異常
│ ├── System.Runtime.InteropServices.MarshalDirectiveException
│ ├── System.Runtime.InteropServices.SafeArrayRankMismatchException
│ └── System.Runtime.InteropServices.SafeArrayTypeMismatchException
│
└── 平台互操作
├── System.Runtime.InteropServices.JavaScript.JSException
└── System.PlatformNotSupportedException
11. UI 與圖形異常
├── WPF與XAML異常
│ ├── System.Windows.Markup.XamlParseException
│ ├── System.Xaml.XamlException
│ ├── System.Windows.Controls.PrintDialogException
│ └── System.Windows.Xps.XpsException
│
├── WinForms異常
│ ├── System.Windows.Forms.AxHost.InvalidActiveXStateException
│ └── System.InvalidOperationException
│
├── 自動化異常
│ ├── System.Windows.Automation.NoClickablePointException
│ └── System.Windows.Automation.ProxyAssemblyNotLoadedException
│
└── UWP/WinUI異常
├── Windows.UI.Xaml.LayoutCycleException
└── Windows.UI.Xaml.Markup.XamlParseException
12. 測試與診斷異常
├── 斷言異常
│ ├── NUnit.Framework.AssertionException
│ ├── xunit.Sdk.XunitException
│ └── Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException
│
├── 事件與日誌異常
│ ├── System.Diagnostics.Eventing.Reader.EventLogException
│ └── System.Diagnostics.Tracing.EventSourceException
│
└── 調試異常
├── System.Diagnostics.UnreachableException
└── System.Runtime.CompilerServices.RuntimeWrappedException
13. 雜項異常
├── 配置異常
│ ├── System.Configuration.Provider.ProviderException
│ ├── System.Configuration.SettingsPropertyIsReadOnlyException
│ └── System.Configuration.SettingsPropertyNotFoundException
│
├── 工作流異常
│ ├── System.Activities.InvalidWorkflowException
│ ├── System.Workflow.ComponentModel.WorkflowTerminatedException
│ └── System.Workflow.Runtime.WorkflowOwnershipException
│
└── 編譯器異常
├── System.Runtime.AmbiguousImplementationException
├── Microsoft.CSharp.RuntimeBinder.RuntimeBinderException
└── System.Web.Query.Dynamic.ParseException
構造函數
重載
| 名稱 | 描述 |
|---|---|
| Exception ( ) | 初始化 Exception 類的新實例 |
| Exception ( string 字符串 ) | 使用指定的錯誤消息初始化 Exception 類的新實例 |
| Exception ( string 字符串 , Exception 內部異常 ) | 使用指定的錯誤消息和對作為此異常原因的內部異常的引用來初始化 Exception 類的新實例 |
public Exception ( );
public Exception ( string? 信息 );
public Exception ( string? 信息 , Exception? 內部異常 );
示例
以下示例派生了一個使用預定義消息的 Exception,演示了派生類與基類 Exception 的無參數構造函數和用法:
class YCH不是偶數 : Exception
{
const string zfc不是偶數信息 = "錯誤:該函數要求參數為偶數,但輸入值不能被 2 整除。";
public YCH不是偶數 ( ) : base ( zfc不是偶數信息 )
{ }
public YCH不是偶數 ( string 有關信息 ) : base ( $"{有關信息} - {zfc不是偶數信息}" )
{ }
}
class NewExceptionDemo
{
public static void Main ( )
{
Console . WriteLine ( "這個 Exception ( ) 構造函數的示例會生成以下輸出。" );
Console . WriteLine ( "\n在此,通過基類的無參數的構造函數拋出了一個異常。\n" );
FF計算一半 ( 12 );
FF計算一半 ( 15 );
Console . WriteLine ( "\n在此,通過使用派生類的無參數構造函數來拋出一個異常。\n" );
FF計算一半2 ( 24 );
FF計算一半2 ( 27 );
}
// 如果輸入的值不是偶數,那麼 FF一半 函數就會拋出一個基本異常
static int FF一半 ( int 輸入值 )
{
if ( 輸入值 % 2 != 0 )
throw new Exception ( $"參數 {輸入值} 不能整除於 2。" );
else return 輸入值 / 2;
}
// FF一半2 會拋出一個衍生異常,如果輸入值不是偶數的話。
static int FF一半2 ( int 輸入值 )
{
if ( 輸入值 % 2 != 0 )
throw new YCH不是偶數 ( $"無效輸入值:{輸入值}" );
else return 輸入值 / 2;
}
// FF計算一半 調用 FF一半 並且會捕獲任何拋出的異常。
static void FF計算一半 ( int 輸入值 )
{
try
{
int yiban = FF一半 ( 輸入值 );
Console . WriteLine ( $"輸入值 {輸入值} 的一半:{yiban}。" );
}
catch ( Exception yc )
{
Console . WriteLine ( yc . ToString ( ) );
}
}
// FF計算一半2 調用 FF一半2 並且會捕獲任何拋出的異常
static void FF計算一半2 ( int 輸入值 )
{
try
{
int yiban = FF一半2 ( 輸入值 );
Console . WriteLine ( $"輸入值 {輸入值} 的一半:{yiban}." );
}
catch ( Exception yc )
{
Console . WriteLine ( yc . ToString ( ) );
}
}
}
以下代碼示例針對特定情況派生了一個 Exception。該代碼展示了派生類和基 Exception 類如何使用以消息和內部異常為參數的構造函數。
LogTable log = new ( 4 );
Console . WriteLine ( "這個 Exception ( string , Exception ) 構造函數的示例會生成以下輸出。" );
Console . WriteLine ( "\n一個引用內部異常的派生異常示例:\n" );
try
{
for ( int zhs = 1 ; ; zhs++ )
{
log . FF添加記錄 ( $"Log 記錄值 {zhs}" ); // 死循環,但 FF添加記錄 在 zhs 為 5 的時候,會拋出異常,退出循環
}
}
catch ( Exception yc )
{
Console . WriteLine ( yc . ToString ( ) );
}
class YCHLog表溢出 : Exception
{
const string zfc溢出信息 = "Log 表發生溢出。";
public YCHLog表溢出 ( ) : base ( zfc溢出信息 ) { }
public YCHLog表溢出 ( string 有關信息 ) : base ( $"{zfc溢出信息} - {有關信息}" ) { }
public YCHLog表溢出 ( string 有關信息 , Exception 內部異常 ) : base ( $"{zfc溢出信息} - {有關信息}" , 內部異常 ) { }
}
class LogTable ( int 數值元素 )
{
protected string [ ] Log區域 = new string [ 數值元素 ];
protected int zhs使用中的元素 = 0;
// 如果捕獲到了數組邊界異常,那麼 “FF添加記錄” 方法就會拋出一個派生自該異常的錯誤
public int FF添加記錄 ( string 新紀錄 )
{
try
{
Log區域 [ zhs使用中的元素 ] = 新紀錄;
return zhs使用中的元素++;
}
catch ( Exception yc )
{
throw new YCHLog表溢出 ( $"記錄 “{新紀錄}” 沒有被記錄。" , yc );
}
}
}
備註
Exception ( )
此構造函數將新實例的 Message 屬性初始化為系統提供的消息,該消息描述錯誤並考慮當前系統區域性。
所有派生類都應提供此無參數構造函數。下表顯示了 Exception 實例的初始屬性值。
| 屬性 | 值 |
|---|---|
| InnerException | null 引用(在 Visual Basic 中為 Nothing) |
| Message | 系統提供的本地化描述 |
Exception ( string 字符串 )
此構造函數通過使用 字符串 參數初始化新實例的 Message 屬性。如果 字符串 參數為 null,則此操作與調用 Exception ( ) 構造函數相同。
下表顯示了Exception實例的初始屬性值。
| 屬性 | 值 |
|---|---|
| InnerException | null 引用(在 Visual Basic 中為 Nothing) |
| Message | 字符串 |
Exception ( string 字符串 , Exception 內部異常 )
作為前一個異常的直接結果而拋出的異常,應在 InnerException 屬性中包含對前一個異常的引用。InnerException 屬性返回傳遞給構造函數的值,或者如果 InnerException 屬性未向構造函數提供內部異常值,則返回 null 引用(在 Visual Basic 中為 Nothing)。
下表顯示了Exception實例的初始屬性值。
| 屬性 | 值 |
|---|---|
| InnerException | 內部異常引用 |
| Message | 字符串 |
屬性
Data
獲取一組 鍵/值 對,這些 鍵/值 對提供有關該異常的其他用户定義信息。
public virtual System . Collections . IDictionary Data { get; }
屬性值
| 屬性值 | 註解 |
|---|---|
| IDictionary | 一個實現了 IDictionary 接口幷包含用户定義的 鍵/值 對集合的對象。默認值是一個 Empty 集合 |
示例
以下示例展示瞭如何使用 Data 屬性添加和檢索信息。
using System . Collections;
Console . WriteLine ( "\n部分擴展信息的異常……" );
FF測試 ( false );
Console . WriteLine ( "\n所有擴展信息的異常……" );
FF測試 ( true );
static void FF測試 ( bool 顯示細節 )
{
try
{
FF嵌套1 ( 顯示細節 );
}
catch ( Exception yc )
{
Console . WriteLine ( "拋出一個異常。" );
Console . WriteLine ( yc . Message );
if ( yc . Data . Count > 0 )
{
Console . WriteLine ( " 擴展細節:" );
foreach ( DictionaryEntry CiDianXiang in yc . Data )
Console . WriteLine ( $" 鍵:{CiDianXiang . Key ,-20} 值:{CiDianXiang . Value}" );
}
}
}
static void FF嵌套1 ( bool 顯示細節 )
{
try
{
FF嵌套2 ( 顯示細節 );
}
catch ( Exception yc )
{
yc . Data [ "擴展信息" ] = "來自 FF嵌套1 的信息。";
yc . Data . Add ( "更多擴展信息" , "來自 FF嵌套1 的更多擴展信息。" );
throw;
}
}
static void FF嵌套2 ( bool 顯示細節 )
{
Exception e = new ( "此陳述即為原始的異常消息。" );
if ( 顯示細節 )
{
string zfc = "來自於 FF嵌套2 的信息。";
int zhs = -903;
DateTime riqishijian = DateTime . Now;
e . Data . Add ( "字符串信息" , zfc );
e . Data [ "整數信息" ] = zhs;
e . Data [ "日期時間信息" ] = riqishijian;
}
throw e;
}
備註
使用 System . Collections . IDictionary 對象(由 Data 屬性返回)來存儲和檢索與該異常相關的補充信息。這些信息以任意數量的用户定義 鍵/值 對形式存在。每個 鍵/值 對中的鍵組件通常是一個標識字符串,而該對中的值組件可以是任何類型的對象。
鍵/值 對安全性
由 Data 屬性返回的集合中存儲的 鍵/值 對並不安全。如果您的應用程序調用一系列嵌套的例程,且每個例程都包含異常處理程序,那麼生成的調用堆棧將包含這些異常處理程序的層次結構。如果較低級別的例程拋出異常,調用堆棧層次結構中任何較高級別的異常處理程序都可以讀取和/或修改該集合中由其他任何異常處理程序存儲的 鍵/值 對。這意味着您必須確保 鍵/值 對中的信息不涉及機密,並且要保證即使 鍵/值 對中的信息被損壞,您的應用程序也能正常運行。
try
{
ProcessSensitiveData ( "admin" , "password123" );
}
catch ( Exception ex )
{
Console . WriteLine ( "捕獲到異常:" );
Console . WriteLine ( ex . Message );
// 危險!直接顯示所有Data信息
if ( ex . Data . Count > 0 )
{
Console . WriteLine ( "\n擴展信息(包含敏感數據):" );
foreach ( DictionaryEntry entry in ex . Data )
{
Console . WriteLine ( $" {entry . Key}: {entry . Value}" );
}
}
}
static void ProcessSensitiveData ( string username , string password )
{
try
{
// 模擬數據庫操作失敗
throw new Exception ( "數據庫連接失敗" );
}
catch ( Exception ex )
{
// 嚴重錯誤!存儲敏感信息到Data
ex . Data [ "Username" ] = username; // 用户名(敏感)
ex . Data [ "Password" ] = password; // 密碼(高度敏感)
ex . Data [ "ConnectionString" ] = "Server=db;Database=secret;User ID=sa;Password=topsecret"; // 連接字符串(高度敏感)
// 錯誤的鍵命名,容易衝突
ex . Data [ "ErrorInfo" ] = "數據庫連接超時";
throw; // 重新拋出異常
}
}
鍵衝突
當不同的異常處理器指定相同的鍵來訪問 鍵/值 對時,就會發生關鍵衝突。在開發應用程序時要小心,因為鍵衝突的後果是較低級別的異常處理器可能會無意中與較高級別的異常處理器進行通信,而這種通信可能會導致難以察覺的程序錯誤。不過,如果你足夠謹慎,就可以利用鍵衝突來增強你的應用程序。
避免鍵衝突
通過採用命名約定為 鍵/值 對生成唯一鍵來避免鍵衝突。例如,命名約定可能會生成一個鍵,該鍵由應用程序的句點分隔名稱、為該對提供補充信息的方法以及唯一標識符組成。
假設兩個應用程序(名為 產品 和 供應商們)都有一個名為 FF銷售 的方法。產品 應用程序中的 FF銷售 方法提供產品的標識號(庫存單位或 SKU)。供應商們 應用程序中的 FF銷售 方法提供供應商的標識號或 SID。因此,本例的命名約定會產生鍵 “產品 . Sales . SKU” 和 “供應商們 . FF銷售 . SID”。
利用鍵衝突
通過使用一個或多個特殊的、預先安排的密鑰的存在來控制處理,從而利用關鍵衝突。假設在某個場景中,調用棧層次結構中最高級別的異常處理器會捕獲所有由較低級別異常處理器拋出的異常。如果存在帶有特殊密鑰的 鍵/值 對,那麼高級異常處理器會以某種非標準的方式格式化 IDictionary 對象中其餘的 鍵/值 對;否則,其餘的 鍵/值 對會以某種常規方式進行格式化。
現在假設有另一種情況,調用棧層次結構中每一級的異常處理程序都會捕獲下一級異常處理程序拋出的異常。此外,每個異常處理程序都知道,Data 屬性返回的集合包含一組 鍵/值 對,這些 鍵/值 對可以通過一組預先安排的鍵來訪問。
每個異常處理器都使用預先安排的鍵集,用該異常處理器特有的信息更新相應 鍵/值 對的 值 部分。更新過程完成後,異常處理器會將異常拋給更高一級的異常處理器。最後,最高級別的異常處理器訪問這些 鍵/值 對,並顯示來自所有較低級別異常處理器的整合更新信息。
using System;
using System.Collections;
// 博客文章:如何利用鍵衝突實現智能錯誤處理
public class KeyConflictUtilizationDemo
{
// 定義特殊鍵(所有模塊都知道這個鍵)
private const string ERROR_PRIORITY_KEY = "Error.Priority";
private const string ERROR_CONTEXT_KEY = "Error.Context";
public static void Main()
{
try
{
// 模擬用户下單流程
ProcessOrder("user123", "product456", 5);
}
catch (Exception ex)
{
Console.WriteLine("=== 頂層錯誤處理 ===");
Console.WriteLine($"錯誤消息: {ex.Message}");
// 利用鍵衝突:檢查優先級
HandleErrorBasedOnPriority(ex);
// 利用鍵衝突:獲取完整上下文
ShowErrorContext(ex);
}
}
static void ProcessOrder(string userId, string productId, int quantity)
{
try
{
// 調用庫存檢查
CheckInventory(productId, quantity);
}
catch (Exception ex)
{
Console.WriteLine("=== 訂單處理層 ===");
// 利用鍵衝突:設置優先級(覆蓋底層設置)
ex.Data[ERROR_PRIORITY_KEY] = "High"; // 高優先級
// 利用鍵衝突:添加上下文信息
ex.Data[ERROR_CONTEXT_KEY] = $"用户:{userId}, 產品:{productId}, 數量:{quantity}";
throw new OrderException("訂單處理失敗", ex);
}
}
static void CheckInventory(string productId, int quantity)
{
try
{
// 模擬庫存不足
throw new Exception("庫存不足");
}
catch (Exception ex)
{
Console.WriteLine("=== 庫存檢查層 ===");
// 利用鍵衝突:設置默認優先級
ex.Data[ERROR_PRIORITY_KEY] = "Normal"; // 默認優先級
// 利用鍵衝突:添加上下文信息
ex.Data[ERROR_CONTEXT_KEY] = $"產品:{productId}, 請求數量:{quantity}, 可用庫存:3";
throw new InventoryException("庫存檢查失敗", ex);
}
}
// 根據優先級處理錯誤
static void HandleErrorBasedOnPriority(Exception ex)
{
if (ex.Data.Contains(ERROR_PRIORITY_KEY))
{
string priority = ex.Data[ERROR_PRIORITY_KEY].ToString();
Console.WriteLine($"\n錯誤優先級: {priority}");
// 根據優先級採取不同行動
switch (priority)
{
case "High":
Console.WriteLine("處理方式: 立即通知管理員 + 記錄詳細日誌");
// NotifyAdmin(ex);
// LogDetailedError(ex);
break;
case "Normal":
Console.WriteLine("處理方式: 記錄常規日誌 + 顯示用户友好消息");
// LogError(ex);
// ShowUserMessage();
break;
}
}
}
// 顯示錯誤上下文信息
static void ShowErrorContext(Exception ex)
{
if (ex.Data.Contains(ERROR_CONTEXT_KEY))
{
string context = ex.Data[ERROR_CONTEXT_KEY].ToString();
Console.WriteLine($"\n錯誤上下文: {context}");
}
}
}
// 自定義異常類
public class OrderException : Exception
{
public OrderException(string message, Exception innerException)
: base(message, innerException) { }
}
public class InventoryException : Exception
{
public InventoryException(string message, Exception innerException)
: base(message, innerException) { }
}
Exception . HelpLink
獲取或設置與此異常相關聯的幫助文件的鏈接。
public virtual string? HelpLink { get; set; }
屬性值
| 屬性值 | 註解 |
|---|---|
| string | 統一資源名稱(URN)或統一資源定位符(URL) |
示例
以下代碼示例會拋出一個異常,該異常在其構造函數中設置了 HelpLink 屬性,然後捕獲該異常並顯示 HelpLink。
namespace HelpLinkExample
{
// 自定義異常類
public class FileProcessingException : Exception
{
public FileProcessingException ( string message , string fileName , Exception innerException )
: base ( $"文件處理錯誤: {message} (文件:{fileName})" , innerException )
{
// 設置幫助鏈接
this . HelpLink = "https://segmentfault.com/u/rabbitcodeman/articles";
this . Source = "FileProcessor";
}
}
class Program
{
static void Main ( string [ ] args )
{
try
{
ProcessFile ( "invalid_file.txt" );
}
catch ( FileProcessingException yc )
{
Console . WriteLine ( $"錯誤信息: {yc . Message}" );
Console . WriteLine ( $"錯誤來源: {yc . Source}" );
Console . WriteLine ( $"幫助鏈接: {yc . HelpLink}" );
Console . WriteLine ( $"調用堆棧: {yc . StackTrace}" );
// 提供用户友好的幫助信息
ShowHelp ( yc );
}
}
static void ProcessFile ( string 文件名 )
{
try
{
// 模擬文件處理錯誤
throw new InvalidOperationException ( "文件格式不正確" );
}
catch ( Exception yc )
{
// 包裝並重新拋出異常,添加HelpLink
throw new FileProcessingException ( "無法讀取文件" , 文件名 , yc );
}
}
static void ShowHelp ( Exception yc )
{
if ( !string . IsNullOrEmpty ( yc . HelpLink ) )
{
Console . WriteLine ( "\n需要幫助嗎?" );
Console . WriteLine ( "1. 打開幫助文檔" );
Console . WriteLine ( "2. 查看錯誤詳情" );
Console . Write ( "請選擇:" );
var choice = Console . ReadLine();
if ( choice == "1" )
{
try
{
Process . Start ( new ProcessStartInfo ( yc . HelpLink )
{
UseShellExecute = true
} );
}
catch
{
Console . WriteLine ( "無法打開幫助鏈接,請手動訪問:" + yc . HelpLink );
}
}
}
}
}
}
備註
返回值表示幫助文件,它是一個 URN 或 URL。例如,HelpLink 的值可以是:
file:///C:/Applications/Baz zal/help.html#Error Num 42
Exception . HResult
獲取或設置 HRESULT,這是一個分配給特定異常的編碼數值。
public int HResult { get; set; }
屬性值
| 屬性值 | 註解 |
|---|---|
| Int32 | HRESULT值 |
示例
以下代碼示例定義了一個派生的 Exception 類,該類在其構造函數中將 HResult 屬性設置為自定義值。
class YCH2 : Exception
{
const int zhs2級結果 = unchecked( ( int ) 0x81234567 );
// 為此次異常設置錯誤結果,並將其包含在異常消息中
/// <summary>
/// 異常 YCH2 的構造函數
/// </summary>
/// <param name="信息">異常信息</param>
/// <param name="實際異常">.NET 實際產生的內部異常</param>
public YCH2 ( string 信息 , Exception 實際異常 ) :
base ( $"(HRESULT:0x{zhs2級結果:X8}) {信息}" , 實際異常 )
{
HResult = zhs2級結果;
}
}
class HResultDemo
{
public static void Main ( )
{
// 此函數會引發除以零的錯誤,並拋出第二個異常
try
{
try
{
int zhs0 = 0;
int zhs除0 = 1 / zhs0;
}
catch ( Exception yc )
{
throw new YCH2 ( "對 0 進行除法運算並引發了第二個異常" , yc );
}
}
catch ( Exception yc )
{
Console . WriteLine ( yc . ToString ( ) );
}
}
}
備註
HRESULT 是一個 32 位的值,分為三個不同的字段:嚴重性代碼、設備代碼和錯誤代碼。嚴重性代碼指示返回值代表信息、警告還是錯誤。設備代碼標識系統中對錯誤負責的區域。錯誤代碼是一個唯一的數字,用於表示異常。每個異常都映射到一個不同的 HRESULT。當託管代碼拋出異常時,運行時會將 HRESULT 傳遞給 COM 客户端。當非託管代碼返回錯誤時,HRESULT 會轉換為異常,然後由運行時拋出。
常見的 HResult 值
以下 HResult 值是常見的,更多的值存在於頭文件 Winerror.h 中。
| 名稱 | 描述 | 值 |
|---|---|---|
| S_OK | Operation successful(操作成功) | 0x00000000 |
| E_ABORT | Operation aborted(操作已中止) | 0x80004004 |
| E_ACCESSDENIED | General access denied error(一般訪問被拒絕錯誤) | 0x80070005 |
| E_FAIL | Unspecified failure(未指定的失敗) | 0x80004005 |
| E_HANDLE | Handle that is not valid(無效的句柄) | 0x80070006 |
| E_INVALIDARG | One or more arguments are not valid(一個或多個參數無效) | 0x80070057 |
| E_NOINTERFACE | No such interface supported(不支持此類接口) | 0x80004002 |
| E_NOTIMPL | Not implemented(未實現) | 0x80004001 |
| E_OUTOFMEMORY | Failed to allocate necessary memory(無法分配必要的內存) | 0x8007000E |
| E_POINTER | Pointer that is not valid(無效指針) | 0x80004003 |
| E_UNEXPECTED | Unexpected failure(意外失敗) | 0x8000FFFF |
從 .NET Framework 4.5 開始,HResult 屬性的 get 是 protected 的,而其 set 是 public 的。在 .NET Framework 的早期版本中,get 和 set 都是 protected 的。
Exception . InnerException
獲取導致當前異常的 Exception 實例。
public Exception? InnerException { get; }
屬性值
| 類型 | 註解 |
|---|---|
| Exception | 一個描述導致當前異常的錯誤的對象。InnerException 屬性返回與傳入 Exception ( String , Exception ) 構造函數的值相同的值,如果未向該構造函數提供內部異常值,則返回 null。此屬性為只讀 |
示例
以下示例演示了拋出和捕獲引用內部異常的異常。
try
{
FF處理實際異常 ( );
}
catch ( LEI應用程序異常 yc )
{
Console . WriteLine ( "在主程序方法中。" );
Console . WriteLine ( $"捕捉到:{yc . Message}" );
if ( yc . InnerException != null )
{ Console . WriteLine ( $"實際異常 . {yc . InnerException}" ); }
}
void FF拋出實際異常 ( )
{
throw new LEI應用程序異常 ( "FF拋出實際異常 引發的異常。" );
}
void FF處理實際異常 ( )
{
try
{
FF拋出實際異常 ( );
}
catch ( LEI應用程序異常 yc )
{ throw new LEI應用程序異常 ( "由於調用了 “FF引發實際異常” 方法,導致了 “FF處理實際異常” 中的錯誤。" , yc ); }
}
class LEI應用程序異常 : Exception
{
public LEI應用程序異常 ( string 信息 ) : base ( 信息 ) { }
public LEI應用程序異常 ( string 信息 , Exception 實際異常 ) : base ( 信息 , 實際異常 ) { }
}
備註
當異常 X 作為先前異常 Y 的直接結果被拋出時,X 的 InnerException 屬性應包含對 Y 的引用。
使用 InnerException 屬性獲取導致當前異常的一系列異常。
你可以創建一個新的異常來捕獲之前的異常。處理第二個異常的代碼可以利用來自之前異常的額外信息,更恰當地處理錯誤。
假設有一個函數用於讀取文件並格式化該文件中的數據。在這個示例中,當代碼嘗試讀取文件時,會拋出一個 IOException。該函數捕獲到 IOException,並拋出一個 FileNotFoundException。IOException 可以保存在 FileNotFoundException 的 InnerException 屬性中,這樣捕獲到 FileNotFoundException 的代碼就能查看初始錯誤的原因。
InnerException 屬性包含對內部異常的引用,它在異常對象初始化時被設置。
意即:當你的 Exception 產生自基本的 .NET 或聲明此 Exception 時未使用 InnerException 參數時,返回的 InnerException 為 null;否則返回聲明時定義的 InnerException。由於其同步性,不可能同時發生兩個以上的異常,因此這兩種情況下 InnerException 不是 null 就是一個 Exception 對象。僅 “AggregateException” 例外,它返回一個 “ReadOnlyCollection < Exception >” ,由於其表示異步操作中的並行任務,所以其可能包含 n 個異常(即同步代碼中的可能同時發生的異常),如需處理,需使用 foreach 遍歷每一個異常。
Exception . Message
獲取描述當前異常的消息。
public virtual string Message { get; }
屬性值
| 類型 | 註解 |
|---|---|
| string | 解釋異常原因的錯誤消息,或空字符串("") |
示例
參閲構造函數中的 Exception ( String ) 方法的示例。
備註
錯誤消息針對的是處理異常的開發人員。Message 屬性的文本應完整描述錯誤,並且在可能的情況下,還應説明如何糾正錯誤。頂級異常處理程序可能會向最終用户顯示該消息,因此你應確保消息語法正確,且每個句子都以句號結尾。不要使用問號或感嘆號。如果你的應用程序使用本地化的異常消息,應確保這些消息已被準確翻譯。
重要提示:在未檢查適當權限的情況下,不要在異常消息中披露敏感信息。
Message 屬性的值包含在 ToString 返回的信息中。Message 屬性僅在創建 Exception 時設置。如果未向當前實例的構造函數提供消息,系統會使用當前系統區域性格式化一條默認消息。
給繼承者的説明
Message 屬性在需要控制消息內容或格式的類中被重寫。應用程序代碼通常在需要顯示有關已捕獲異常的信息時訪問此屬性。
錯誤消息應本地化。
Exception . Source
獲取或設置導致錯誤的應用程序或對象的名稱。
public virtual string? Source { get; set; }
屬性值
| 類型 | 註解 |
|---|---|
| string | 導致錯誤的應用程序或對象的名稱 |
異常
| 異常 | 註解 |
|---|---|
| ArgumentException | 該對象必須是運行時 System . Reflection 對象 |
示例
LogTable log = new ( 4 );
Console . WriteLine ( "這個關於\n Exception . Message、\n Exception . HelpLink、\n Exception . Source、\n Exception . StackTrace 以及\n Exception . TargetSite 的示例會生成以下輸出。" );
try
{
for ( int zhs = 1 ; ; zhs++ )
{
log . FF添加記錄 ( $"Log 記錄值 {zhs}" ); // 死循環,但 FF添加記錄 在 zhs 為 5 的時候,會拋出異常,退出循環
}
}
catch ( Exception yc )
{
Console . WriteLine ( $"\nMessage ---\n{yc . Message}" );
Console . WriteLine ( $"\nHelpLink ---\n{yc . HelpLink}" );
Console . WriteLine ( $"\nSource ---\n{yc . Source}" );
Console . WriteLine ( $"\nStackTrace ---\n{yc . StackTrace}" );
Console . WriteLine ( $"\nTargetSite ---\n{yc . TargetSite}" );
}
class YCHLog表溢出 : Exception
{
const string zfc溢出信息 = "Log 表發生溢出。";
public YCHLog表溢出 ( ) : base ( zfc溢出信息 ) { }
public YCHLog表溢出 ( string 有關信息 ) : base ( $"{zfc溢出信息} - {有關信息}" ) { }
public YCHLog表溢出 ( string 有關信息 , Exception 內部異常 ) : base ( $"{zfc溢出信息} - {有關信息}" , 內部異常 )
{
this . HelpLink = "https://segmentfault.com/u/rabbitcodeman/articles";
this . Source = "C# 的異常 示例";
}
}
class LogTable ( int 數值元素 )
{
protected string [ ] Log區域 = new string [ 數值元素 ];
protected int zhs使用中的元素 = 0;
// 如果捕獲到了數組邊界異常,那麼 “FF添加記錄” 方法就會拋出一個派生自該異常的錯誤
public int FF添加記錄 ( string 新紀錄 )
{
try
{
Log區域 [ zhs使用中的元素 ] = 新紀錄;
return zhs使用中的元素++;
}
catch ( Exception yc )
{
throw new YCHLog表溢出 ( $"記錄 “{新紀錄}” 沒有被記錄。" , yc );
}
}
}
備註
如果未顯式設置 Source 屬性,運行時會自動將其設置為異常起源的程序集的名稱。
Exception . StackTrace
獲取調用棧上直接幀的字符串表示形式。
public virtual string? StackTrace { get; }
屬性值
| 類型 | 註解 |
|---|---|
| String | 一個描述調用棧即時幀的字符串。如果沒有可用的棧跟蹤(例如在從 throw 語句展開堆棧之前),則該值為 null |
示例
參見 Exception . Source 的示例。
備註
執行棧會跟蹤在特定時刻所有正在執行的方法。方法調用的軌跡稱為棧跟蹤。棧跟蹤列表提供了一種沿着調用棧追蹤到異常發生所在方法的行號的方式。
StackTrace 屬性返回源自拋出異常位置的調用堆棧幀。您可以通過創建 System . Diagnostics . StackTrace 類的新實例並使用其 StackTrace . ToString 方法來獲取有關調用堆棧中其他幀的信息。
公共語言運行時(CLR)在應用程序代碼中拋出異常時(通過使用 throw 關鍵字),會更新堆棧跟蹤。如果異常在與最初拋出它的方法不同的方法中被重新拋出,那麼堆棧跟蹤將同時包含異常最初拋出時所在方法中的位置以及異常被重新拋出時所在方法中的位置。如果異常在同一個方法中被拋出後又被重新拋出,堆棧跟蹤將只包含異常被重新拋出的位置,而不包括異常最初拋出的位置。
由於優化過程中會發生內聯等代碼轉換,StackTrace 屬性可能不會像預期那樣報告那麼多方法調用。
給繼承者的説明
StackTrace 屬性在需要控制堆棧跟蹤內容或格式的類中被重寫。
默認情況下,堆棧跟蹤是在拋出異常對象之前立即捕獲的。當沒有拋出異常時,請使用 StackTrace 來獲取堆棧跟蹤信息。
Exception . TargetSite
獲取引發當前異常的方法。
public System . Reflection . MethodBase? TargetSite
{
[ System . Diagnostics . CodeAnalysis . RequiresUnreferencedCode ( "該方法的元數據可能不完整或者已被刪除" ) ] get;
}
屬性值
| 類型 | 註解 |
|---|---|
| MethodBase? | 引發當前異常的 MethodBase |
Attributes(屬性)
RequiresUnreferencedCodeAttribute
示例
參見 Exception . Source 的示例。
備註
如果拋出此異常的方法不可用且棧跟蹤不是 null 引用(在 Visual Basic 中為 Nothing),則 TargetSite 會從棧跟蹤中獲取該方法。如果棧跟蹤是 null 引用,TargetSite 也會返回 null 引用。
注意:如果異常處理程序跨應用程序域邊界處理異常,TargetSite 屬性可能無法準確報告拋出異常的方法名稱。
方法
Exception . GetBaseException
在派生類中重寫時,返回作為一個或多個後續異常根本原因的 Exception。
public virtual Exception GetBaseException ( );
返回值
| 類型 | 註解 |
|---|---|
| Exception | 在異常鏈中拋出的第一個異常。如果當前異常的 InnerException 屬性是 null 引用(在 Visual Basic 中為 Nothing),則此屬性返回當前異常 |
示例
// 定義兩個派生異常以演示嵌套異常的情況
class YCH2 ( string 信息 , Exception 實際異常 ) : Exception ( 信息 , 實際異常 )
{
}
class YCH3 ( string 信息 , Exception 實際異常 ) : Exception ( 信息 , 實際異常 )
{
}
class NestedExceptions
{
public static void Main ( )
{
Console . WriteLine ( "這個 “Exception . GetBaseException” 示例會生成以下輸出。" );
Console . WriteLine ( "\n該程序會引發除以零的錯誤,然後再次拋出該錯誤兩次,每次使用的都是不同的派生異常類型。\n" );
try
{
// 此函數會調用另一個函數,而該函數會進行除以零的運算
FF重新拋出 ( );
}
catch ( Exception yc )
{
Exception? yc當前;
Console . WriteLine ( "通過使用 “InnerException” 屬性來展開嵌套的異常:\n" );
// 此代碼通過 “InnerException” 屬性來解除嵌套異常的關聯
yc當前 = yc;
while ( yc當前 != null )
{
Console . WriteLine ( yc當前 . ToString ( ) );
Console . WriteLine ( );
yc當前 = yc當前 . InnerException;
}
// 顯示最底層的異常
Console . WriteLine ( "使用 “GetBaseException” 方法顯示基本異常:\n" );
Console . WriteLine ( yc . GetBaseException ( ) . ToString ( ) );
}
}
// 此函數會捕獲被調用函數 FF除0 ( ) 所拋出的異常,並相應地拋出另一個異常
static void FF重新拋出 ( )
{
try
{
FF除0 ( );
}
catch ( Exception yc )
{
throw new YCH3 ( "捕獲了第二個異常,並相應地拋出了第三個異常" , yc );
}
}
// 此函數會引發除以零的錯誤,並拋出第二個異常
static void FF除0 ( )
{
try
{
int zhs0 = 0;
int zhs除0 = 1 / zhs0;
}
catch ( Exception yc )
{
throw new YCH2 ( "對 0 進行除法運算並引發了第二個異常。" , yc );
}
}
}
備註
異常鏈由一組異常組成,其中鏈中的每個異常都是因其 InnerException 屬性所引用的異常而直接拋出的。對於給定的鏈,恰好有一個異常是鏈中所有其他異常的根本原因。這個異常被稱為基礎異常,其 InnerException 屬性始終包含一個 null 引用。
對於異常鏈中的所有異常,GetBaseException 方法必須返回相同的對象(基礎異常)。
當你想要查找異常的根本原因,但不需要了解當前異常與第一個異常之間可能發生的異常相關信息時,請使用 GetBaseException 方法。
調用者説明
在需要控制異常內容或格式的類中,會重寫 GetBaseException 方法。
Exception . GetType
獲取當前實例的運行時類型。
public Type GetType ( );
返回值
| 類型 | 註解 |
|---|---|
| Type | 一個 Type 對象,它表示當前實例的確切運行時類型 |
示例
Exception yc = new ( "未知的異常!" );
ArgumentException yc參數 = new ( "參數異常!" );
Console . WriteLine ( yc . GetType ( ) );
Console . WriteLine ( yc參數 . GetType ( ) );
備註
GetType 方法的存在是為了支持 .NET Framework 基礎設施,它在內部調用基本方法 Object . GetType。
Exception . ToString
創建並返回當前異常的字符串表示形式。
public override string ToString ( );
返回值
| 類型 | 註解 |
|---|---|
| string | 當前異常的字符串表示形式 |
備註
ToString 返回當前異常的表示形式,旨在讓人類能夠理解。如果異常包含對區域性敏感的數據,則 ToString 返回的字符串表示形式需要考慮當前系統區域性。儘管對返回字符串的格式沒有確切要求,但它應嘗試反映用户所感知的對象值。
ToString 的默認實現會獲取引發當前異常的類的名稱、消息、對內部異常調用 ToString 的結果以及調用 Environment . StackTrace 的結果。如果這些成員中的任何一個為 null,則其值不會包含在返回的字符串中。
如果沒有錯誤消息,或者錯誤消息是空字符串(""),則不返回錯誤消息。僅當內部異常的名稱和堆棧跟蹤不為 null 時,才會返回它們。
此方法重寫了 Object . ToString。
ArgumentException
當提供給方法的參數之一無效時引發的異常。
public class ArgumentException : SystemException
繼承
| Object | Exception | SystemException | ArgumentException |
|---|
派生
System.ArgumentException
├── System.ArgumentNullException
├── System.ArgumentOutOfRangeException
│ └── System.ComponentModel.Design.CheckoutException
├── System.ComponentModel.InvalidAsynchronousStateException
├── System.ComponentModel.InvalidEnumArgumentException
├── System.DuplicateWaitObjectException
├── System.Globalization.CultureNotFoundException
├── System.IO.Log.ReservationNotFoundException
├── System.Text.DecoderFallbackException
├── System.Text.EncoderFallbackException
└── System.Text.RegularExpressions.RegexParseException
示例
int [ ] ZHSs = [ 12 , 23 ];
foreach ( var zhs in ZHSs )
{
try
{
Console . WriteLine ( $"{zhs} 整除 2 是:is {FF除2 ( zhs )}" );
}
catch ( ArgumentException yc )
{
Console . WriteLine ( $"{yc . GetType ( ) . Name}:{yc . Message}" );
}
}
備註
當調用方法且至少有一個傳遞的參數不符合被調用方法的參數規範時,會引發 ArgumentException。ParamName 屬性用於標識無效的參數。
最常見的情況是,ArgumentException 由公共語言運行時(CLR)或其他類庫拋出,表明存在開發人員錯誤。如果從你的代碼中拋出 ArgumentException,則應確保該異常的 Message 屬性包含有意義的錯誤消息,該消息描述無效參數以及該參數的預期值範圍。
ArgumentException 的主要派生類是 ArgumentNullException 和 ArgumentOutOfRangeException。應使用這些派生類,而非 ArgumentException,除非在這兩個派生類都不適用的情況下。例如,應在以下情況拋出異常:
- 當將 null 傳遞給不接受其作為有效參數的方法時,會出現 ArgumentNullException。
- 當參數值超出可接受範圍時,會發生 ArgumentOutOfRangeException;例如,在創建 DateTime 時,將值 “46” 作為月份參數傳遞。
如果方法調用沒有任何參數,或者失敗不涉及參數本身,則應使用 InvalidOperationException。
ArgumentException 使用 HRESULT COR_E_ARGUMENT,其值為 0x80070057。
在 F# 中,您可以使用 invalidArg 函數來生成並引發 ArgumentException。
構造函數
| 構造函數 | 備註 |
|---|---|
| ArgumentException ( ) | 初始化 ArgumentException 類的新實例 |
| ArgumentException ( String 初始化信息 ) | 使用指定的錯誤消息初始化 ArgumentException 類的新實例 |
| ArgumentException ( String 初始化信息 , Exception 實際異常 ) | 使用指定的錯誤消息和對導致此異常的內部異常的引用來初始化 ArgumentException 類的新實例 |
| ArgumentException ( String 初始化信息 , String 參數名稱 ) | 使用指定的錯誤消息和導致此異常的參數的名稱來初始化 ArgumentException 類的新實例 |
| ArgumentException ( String 初始化信息 , String 參數名稱 , Exception 實際異常 ) | 使用指定的錯誤消息、參數名以及對導致此異常的內部異常的引用來初始化 ArgumentException 類的新實例 |
public ArgumentException ( );
public ArgumentException ( string? 初始化信息 );
public ArgumentException ( string? 初始化信息 , Exception? 實際異常 );
public ArgumentException ( string? 初始化信息 , nameof ( 參數名稱 ) );
public ArgumentException ( string? 初始化信息 , string? 參數名稱 , Exception? 實際異常 );
參數
| 參數 | 類型 | 註解 |
|---|---|---|
| 初始化信息 | string | 解釋異常原因的錯誤消息 |
| 實際異常 | Exception | 作為當前異常原因的異常。如果 實際異常 參數不是 null 引用,則當前異常會在處理內部異常的 catch 塊中引發 |
| 參數名稱 | string | 導致當前異常的參數名稱 |
示例
下面的示例使用 ArgumentException 的帶有 初始化信息 和 實際異常 參數的構造函數構造一個實例。
int [ ] ZHSs = [ 1234 , 123 , 16 , 7 ];
foreach ( var zhs in ZHSs )
{
try
{
if ( zhs % 2 == 0 )
{
Console . WriteLine ( $"{zhs} 是個偶數!" );
}
else
{
throw new ArgumentException ( "這不是個偶數,不能整除於 2!\t" , new Exception ( "不是偶數" ) );
}
}
catch ( ArgumentException yc ) { Console . WriteLine ( $"\t{zhs} :{yc . Message}\t{yc . InnerException}" ); }
}
以下示例使用 ArgumentException 的帶有 初始化信息 和 參數名稱 參數的構造函數構造一個實例。
int [ ] ZHSs = [ 7 , 8 , 9 , 10 ];
foreach ( int z in ZHSs )
try
{
Console . WriteLine ( FF整除 ( z , 3 ) );
}
catch ( ArgumentException yc )
{
Console . WriteLine ( yc );
}
static int FF整除 ( int 整數 , int 除數 )
{
if ( ( 整數 % 除數 ) != 0 )
throw new ArgumentException ( "整數必須能被除數整除" , nameof ( 整數 ) );
return 整數 / 除數;
}
備註
初始化信息 和 參數名稱 是為用户能夠理解該 ArgumentException 的信息,若為 null,則使用未被本地化的默認 ArgumentException Message,和/或 參數名稱 返回 null。若指定 初始化信息 參數,調用方需要確保該字符串已針對當前系統區域性進行了本地化。參數名稱 參數必須是產生該異常的範圍內已聲明的參數名稱。
作為前一個異常的直接結果而拋出的異常,應在 實際異常 屬性中包含對前一個異常的引用。實際異常 屬性返回傳遞給構造函數的值,或者如果 實際異常 屬性未向構造函數提供內部異常值,則返回 null。
| 方法 | 屬性 | 值 |
|---|---|---|
| 無參數 | InnerException | null 引用(Visual Basic 中為 Nothing) |
| 初始化信息 | 本地化的錯誤消息字符串 | |
| 參數名稱 | ("") | |
| 僅 初始化信息 | InnerException | null 引用(Visual Basic 中為 Nothing) |
| 初始化信息 | 初始化信息 | |
| 參數名稱 | ("") | |
| 初始化信息 和 實際異常 | InnerException | 引用 實際異常 |
| 初始化信息 | 初始化信息 | |
| 參數名稱 | ("") | |
| 初始化信息 和 參數名稱 | InnerException | null 引用(Visual Basic 中為 Nothing) |
| 初始化信息 | 初始化信息 | |
| 參數名稱 | 參數名稱(格式化為 (Parameter '參數名稱') | |
| 初始化信息、參數名稱 和 實際異常 | InnerException | 引用 實際異常 |
| 初始化信息 | 初始化信息 | |
| 參數名稱 | 參數名稱(格式化為 (Parameter '參數名稱') |
ArgumentException . Message
獲取錯誤消息和參數名稱;如果未設置參數名稱,則僅獲取錯誤消息。
public override string Message { get; }
屬性值
| 類型 | 註解 | |
|---|---|---|
| string | 一個描述異常詳情的文本字符串。此屬性的值有兩種形式之一: | |
| 條件 | 值 | |
| 參數名稱 為 null 引用或("") | 傳遞給構造函數的 初始化信息 字符串 | |
| 參數名稱 不為 null 引用或("") | 傳遞給構造函數的 初始化信息 字符串並附加了無效參數名 |
備註
此屬性重寫 初始化信息。錯誤消息應進行本地化。
ArgumentException . ParamName
獲取導致此異常的參數的名稱。
public virtual string? ParamName { get; }
屬性值
| 類型 | 註解 |
|---|---|
| string | 導致該異常的參數名 |
註解
每個 ArgumentException 都應包含導致此異常的參數名稱。
此屬性為只讀,返回的值與傳入構造函數的值相同。重寫方法應僅用於自定義參數名稱的格式。
出於本地化目的,參數名稱不應被翻譯。
方法
ThrowIfNullOrEmpty 和 ThrowIfNullOrWhiteSpace
兩個方法均只可接受 string? 參數。ThrowIfNullOrEmpty 在參數為 null 或 Empty 時拋出異常。ThrowIfNullOrWhiteSpace 在參數為 null 或只有空格存在或 Empty 時拋出異常。
public static void ThrowIfNullOrEmpty ( string? 參數 , string? 參數名 = default );
public static void ThrowIfNullOrWhiteSpace ( string? 參數 , string? 參數名 = default );
參數
| 參數 | 類型 | 註解 |
|---|---|---|
| 參數 | string? | 欲驗證的字符串 |
| 參數名 | string? | 拋出異常的參數名稱,若為 null 或未指定,則為 參數 原名 |
拋出異常
| 方法 | 異常 | 註解 |
|---|---|---|
| ThrowIfNullOrEmpty | ArgumentException | 參數 為 String . Empty |
| ArgumentNullException | 參數 為 null | |
| ThrowIfNullOrWhiteSpace | ArgumentException | 參數 為 String . Empty 或僅有空白字符(Unicode 定義)組成 |
| ArgumentNullException | 參數 為 null |
示例
以下示例演示了判斷一個字符串數組中每個元素的組成(例如是否有效),當為 null、String . Empty 或僅由空白字符組成,指出其位置:
string? [ ] ZFCs = [ null , "" , "abcd" , " " ];
for ( int i = 0 ; i < ZFCs . Length ; i++ )
{
try
{
ArgumentException . ThrowIfNullOrEmpty ( ZFCs [ i ] );
ArgumentException . ThrowIfNullOrWhiteSpace ( ZFCs [ i ] , "僅空格的元素" ); // 使用 參數名 字段標明該元素不是 null 或 Empty,但只有空白字符
Console . WriteLine ( $"第 {i + 1} 個元素是:{ ZFCs [ i ]}" ); // 上述方法均未拋出異常,顯示該字符串
}
catch ( ArgumentNullException ) { Console . WriteLine ( $"第 {i + 1} 個元素為 Null。" ); }
catch ( ArgumentException yc ) // 使用字符串的長度判斷是否是空白字符組成的
{
if ( ZFCs [ i ]! . Length > 0 )
Console . WriteLine ( $"第 {i + 1} 個元素為{yc . ParamName}。" ); // 演示了 參數名 字段的用途
else
Console . WriteLine ( $"第 {i + 1} 個元素為 Empty。" );
}
}
備註
兩個方法的 參數 參數為 null 時,均拋出 ArgumentNullException;兩個方法的 參數 參數為 String . Empty 時,均拋出 ArgumentException;當 參數 參數為僅由空白字符(Unicode 定義)組成時,ThrowIfNullOrWhiteSpace 會拋出 ArgumentException,ThrowIfNullOrEmpty 不會拋出異常。
示例中演示了判斷所有不正常字符串(null、Empty 和 空白字符)的過程,實際上,本例是演示了兩種方法,但使用 ThrowIfNullOrWhiteSpace 一個方法即可完成示例的要求,因為 ThrowIfNullOrEmpty 方法不會判斷僅由空白字符組成的字符串。
ArgumentNullException
當 null 引用(Visual Basic 中為 Nothing)被傳遞給不接受其作為有效參數的方法時引發的異常。
public class ArgumentNullException : ArgumentException
繼承
| Object | Exception | SystemException | ArgumentException | ArgumentNullException |
|---|
備註
當某方法的某參數(至少一個)不能為 null,但調用方法時傳遞給該參數的值為 null,即會拋出 ArgumentNullException 異常。
在以下兩種主要情況下,運行時會拋出 ArgumentNullException 異常,這兩種情況都反映了開發人員的錯誤:
- 一個未實例化的對象被傳遞給了一個方法。要防止此錯誤,請實例化該對象。
- 一個從方法調用返回的對象隨後被作為參數傳遞給第二個方法,但原始返回對象的值為 null。為防止出錯,請檢查返回值是否為 null,僅當返回值不為 null 時才調用第二個方法。
ArgumentNullException 的行為與 ArgumentException 完全相同。提供它是為了讓應用程序代碼能夠區分由 null 參數引起的異常和由非 null 參數引起的異常。
ArgumentNullException 使用 HRESULT E_POINTER,其值為 0x80004003。
構造函數
| 構造函數 | 備註 |
|---|---|
| ArgumentNullException ( ) | 初始化 ArgumentNullException 類的新實例 |
| ArgumentNullException ( String 參數名稱 ) | 使用導致此異常的參數的名稱初始化 ArgumentNullException 類的新實例 |
| ArgumentNullException ( String 參數名稱 , String 初始化信息 ) | 使用指定的錯誤消息和導致此異常的參數的名稱初始化 ArgumentNullException 類的新實例 |
| ArgumentNullException ( String 初始化信息 , Exception 實際異常 ) | 使用指定的錯誤消息和導致此異常的實際異常初始化 ArgumentNullException 類的新實例 |
參數
| 參數 | 類型 | 註解 |
|---|---|---|
| 參數名稱 | string | 導致此異常的參數的名稱 |
| 初始化信息 | string | 指定的錯誤消息 |
| 實際異常 | Exception | 導致此異常的實際異常 |
示例
以下示例演示了沒有參數的構造函數:
ArgumentNullException ycNull = new ( );
try { throw ycNull; }
catch ( ArgumentException e ) { Console . WriteLine ( e . ToString ( ) ); }
沒有任何參數初始化的 ArgumentNullException 的 ToString 永遠顯示:System.ArgumentNullException: Value cannot be null.。
以下示例演示瞭如何使用一個 string 參數指定引發 ArgumentNullException 的參數:
Console . OutputEncoding = System . Text . Encoding . UTF8 ;
try
{
string? ZFC = null; // 可以是任意值
int? ZHS = null; // 可以是任意值
FF測試ArgumentNullException ( ZFC , ZHS );
}
catch ( ArgumentNullException ycNull ) { Console . WriteLine ( ycNull . ToString ( ) ); }
static void FF測試ArgumentNullException ( string? zfc , int? zhs )
{
if ( zhs == null && zfc == null ) // 兩個參數都為 null,沒有輸出,但有 ArgumentNullException 提示
throw new ArgumentNullException ( $"{nameof ( zfc )}\t{nameof ( zhs )}" , "字符串參數和整數參數均為 null。" );
else if ( zhs == null ) // 僅輸出 zfc,但 ArgumentNullException 提示 zhs 是 null
{
Console . WriteLine ( zfc );
throw new ArgumentNullException ( nameof ( zhs ) , "整數參數為 null。" );
}
else if ( zfc == null ) // 僅輸出 zhs,但 ArgumentNullException 提示 zfc 是 null
{
Console . WriteLine ( zhs );
throw new ArgumentNullException ( nameof ( zfc ) , "字符串參數為 null。" );
}
else // 沒有異常,輸出字符串,整數
Console . WriteLine ( $"{zfc},{zhs}" );
}
以下示例創建了一個帶有 InnerException 參數的 ArgumentNullException:
Console . OutputEncoding = System . Text . Encoding . UTF8 ;
try
{
FF測試 ( null );
}
catch ( ArgumentException yc )
{
Console . WriteLine ( "外部異常消息: " + yc . Message );
Console . WriteLine ( "內部異常消息: " + yc . InnerException? . Message );
}
static void FF測試 ( string? 輸入 )
{
if ( 輸入 == null )
{
throw new ArgumentNullException ( "輸入參數無效" , new Exception ( "內部詳細原因:參數為 null" ) );
}
}
下面的例程描述瞭如何為 “Value cannot be null.” 區域化的過程:
Console . OutputEncoding = System . Text . Encoding . UTF8 ;
try
{
//Thread . CurrentThread . CurrentCulture = new System . Globalization . CultureInfo ( "ja-JP" );
//Thread . CurrentThread . CurrentUICulture = new System . Globalization . CultureInfo ( "ja-JP" );
Dictionary<string, string> CDs錯誤消息 = new ( )
{
{ "中國", "值不能為 null。" },
{ "日本", "値を null にすることはできません。" }
};
if ( Thread . CurrentThread . CurrentUICulture . Name == "ja-JP" )
throw new ArgumentNullException ( "" , CDs錯誤消息 [ "日本" ] );
else
throw new ArgumentNullException ( "" , CDs錯誤消息 [ "中國" ] );
}
catch ( Exception yc ) { Console . WriteLine ( yc . Message ); }
備註
無參數的構造函數將 實例 的 Message 屬性初始化為系統提供的描述錯誤的消息,例如 “Value cannot be null.”。
一個 string 參數的構造函數將 實例 的 InnerException 屬性賦值為該參數(與 ArgumentException 不同)。
兩個 string 參數的構造函數將 實例 的 InnerException 屬性賦值為第一個參數;初始化消息賦值為第二個參數(與 ArgumentException 不同)。
一個 string 和一個 Exception 參數的構造函數將 實例 的 Message 屬性賦值為 string 參數,InnerException 屬性賦值為 Exception 參數。
下表顯示了 ArgumentNullException 實例的初始屬性值。
| 參數 | 屬性 | 值 |
|---|---|---|
| 無 | 實際異常 | null 引用(Visual Basic 中為 Nothing) |
| Message | 一個本地化的錯誤消息字符串,例如英語的 “Value cannot be null.” | |
| ParamName | String . Empty | |
| 參數名稱 | 實際異常 | null 引用(Visual Basic 中為 Nothing) |
| Message | 一個本地化的錯誤消息字符串,例如英語的 “Value cannot be null.” | |
| ParamName | 參數名稱 | |
| 參數名稱 和 初始化信息 | 實際異常 | null 引用(Visual Basic 中為 Nothing) |
| Message | 初始化信息 | |
| ParamName | 參數名稱 | |
| 初始化信息 和 實際異常 | 實際異常 | 實際異常 |
| Message | 初始化信息 | |
| ParamName | String . Empty |
方法
ArgumentNullException . ThrowIfNull
如果 參數 為 null,則拋出 ArgumentNullException。
public static void ThrowIfNull ( object? 參數 , string? 參數名 = default );
參數
| 參數 | 類型 | 註解 |
|---|---|---|
| 參數 | object? | 要驗證為非 null 的引用類型參數 |
| 參數名 | string? | 與 參數 對應的參數名稱。如果省略此參數,則使用 參數 的名稱 |
引發異常
| 異常 | 註解 |
|---|---|
| ArgumentNullException | 參數 為 null |
備註
包含 參數名 參數是為了支持 CallerArgumentExpressionAttribute 屬性。建議不要為該參數傳遞值,而是使用 參數 的名稱。
ArgumentOutOfRangeException
當參數值超出被調用方法所定義的允許值範圍時拋出的異常。
public class ArgumentOutOfRangeException : ArgumentException
繼承
| Object | Exception | SystemException | ArgumentException | ArgumentOutOfRangeException |
|---|
示例
以下示例定義了一個類,包含招聘員工的信息。如果應聘人員小於 18 歲或大於 35 歲,則拋出 ArgumentOutOfRangeException 異常。
Console . OutputEncoding = System . Text . Encoding . UTF8 ;
LEI應聘人員 [ ] YingPins = [
new LEI應聘人員 ( "歐陽" , "飛飛" , false , 27 ),
new LEI應聘人員 ( "夏侯" , "瀟瀟" , false , 17 ),
new LEI應聘人員 ( "東方" , "月明" , true , 29 ),
new LEI應聘人員 ( "西門" , "太郎" , true , 38 ),
];
List < LEI應聘人員 > LB面試 = [ ];
Console . WriteLine ( "下面是淘汰者:" );
foreach ( var yp in YingPins )
{
try
{
if ( yp . 年齡 > LEI應聘人員 . zhs最大年齡 || yp . 年齡 < LEI應聘人員 . zhs最小年齡 )
{
Console . WriteLine ( yp . 信息 );
throw new ArgumentOutOfRangeException ( null , $"應聘者的年齡必須在 {LEI應聘人員 . zhs最小年齡} ~ {LEI應聘人員 . zhs最大年齡} 之間。" );
}
LB面試 . Add ( yp );
}
catch ( ArgumentOutOfRangeException yc )
{
Console . WriteLine ( $"錯誤:{yc . Message}" );
}
}
Console . WriteLine ( "\n下面是面試者:" );
foreach ( var mianshi in LB面試 )
Console . WriteLine ( $"面試者:{mianshi . 信息}" );
class LEI應聘人員
{
public const int zhs最小年齡 = 18;
public const int zhs最大年齡 = 35;
private string _zfc姓 , _zfc名;
private int _zhs年齡;
private bool _ber性別;
public LEI應聘人員 ( string 姓 , string 名 , bool 性別 , int 年齡)
{
_zfc姓 = 姓;
_zfc名 = 名;
_ber性別 = 性別;
_zhs年齡 = 年齡;
}
public int 年齡
{
get { return _zhs年齡; }
}
public string 信息 => $"{_zfc姓}{_zfc名},{(_ber性別 ? "男" : "女")},{_zhs年齡} 歲";
}
備註
當調用方法且傳遞給該方法的至少一個參數不是 null,並且包含一個無效值(該值不屬於該參數預期值集合的成員)時,會引發 ArgumentOutOfRangeException 異常。ParamName 屬性標識無效參數,如果存在值,ActualValue 屬性則標識無效值。
通常,ArgumentOutOfRangeException 是由開發人員錯誤導致的。不應在 try/catch 塊中處理該異常,而應消除導致異常的原因;或者,如果參數是由方法調用返回的,或者是在傳遞給引發異常的方法之前由用户輸入的,則應在將參數傳遞給該方法之前對其進行驗證。
ArgumentOutOfRangeException 被廣泛用於:
- System.Collections 和 System.IO 命名空間中的類。
- Array類。
- String 類中的字符串操作方法。
拋出 ArgumentOutOfRangeException 異常的情況包括以下幾種:
-
您正通過索引編號檢索集合的成員,但該索引編號無效。
這是 ArgumentOutOfRangeException 異常最常見的原因。通常情況下,索引編號無效有四個原因之一:-
該集合沒有成員,但您的代碼卻假設它有。以下示例嘗試檢索一個沒有元素的集合的第一個元素:
List < int > LBZHSs = [ ]; Console . WriteLine ( $"LBZHSs 中的項目數:{LBZHSs . Count}" ); try { Console . WriteLine ( $"第一個項目:{LBZHSs [ 0 ]}" ); } catch ( ArgumentOutOfRangeException yc ) { Console . WriteLine ( yc . Message ); }為防止此異常,應在檢索任意成員之前,首先檢查集合的 Count 屬性是否大於零:
if ( list . Count > 0 ) { Console . WriteLine ( $"第一個項目:‘{list [ 0 ]}’" ); -
在某些情況下,出現此異常可能是因為你嘗試使用不存在的索引向集合添加成員,而不是調用為此目的存在的方法(如 Add)。以下示例嘗試使用不存在的索引向集合添加元素,而不是調用 List < T > . Add 方法。
List < int > LBZHSs = [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 20 ]; List < double > LBSJDs = [ ]; for ( int z = 0 ; z < LBZHSs . Count ; z++ ) { try { LBSJDs [ z ] = Math . Pow ( ( double ) LBZHSs [ z ] , 0.5 ); } catch ( ArgumentOutOfRangeException yc ) { Console . Error . WriteLine ( yc . Message ); break; } }修正後的代碼:
List < int > LBZHSs = [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 20 ]; List < double > LBSJDs = [ ]; for ( int z = 0 ; z < LBZHSs . Count ; z++ ) { try { LBSJDs . Add ( Math . Pow ( ( double ) LBZHSs [ z ] , 0.5 ) ); } catch ( ArgumentOutOfRangeException yc ) { Console . Error . WriteLine ( yc . Message ); break; } } Console . WriteLine ( $"{String . Join ( ',' , LBSJDs )};" ); -
你正試圖檢索索引為負數的項。這通常是因為你在集合中搜索某個特定元素的索引時,錯誤地假設搜索成功了。在下面的示例中,調用 List < T > . FindIndex ( Predicate < T > ) 方法未能找到等於 “Z” 的字符串,因此返回 -1。但這是一個無效的索引值。
List < string > LBZFCs = [ "A" , "B" , "C" ]; int zhs索引Z = LBZFCs . FindIndex ( ( new LEI字符串搜索 ( "Z" ) ) .FF查找相同 ); try { Console . WriteLine ( $"索引 {zhs索引Z} 處包含 {LBZFCs [ zhs索引Z ]}" ); } catch ( ArgumentOutOfRangeException yc ) { Console . WriteLine ( yc . Message ); } internal class LEI字符串搜索 ( string 值 ) { private readonly string zfc = 值; public bool FF查找相同 ( string 值 ) { return 值 . Equals ( zfc , StringComparison . InvariantCulture ); } }為防止出現異常,應像以下代碼片段所示,在嘗試從集合中檢索項目之前,通過確保返回的索引大於或等於零來檢查搜索是否成功。
if (zhs索引Z >= 0) {Console . WriteLine ( $"'Z' 在索引 {zhs索引Z} 處找到。" ); -
您正嘗試檢索索引等於集合的 Count 屬性值的元素,如下例所示。
List < int > LBZHSs = [ 0 , 1 , 2 ]; try { for ( int z = 0 ; z <= LBZHSs . Count ; z++ ) { Console . WriteLine ( $"索引 {z}:{LBZHSs [ z ]}" ); } } catch ( ArgumentOutOfRangeException yc ) { Console . WriteLine ( yc . Message ); }由於 .NET 中的集合使用從零開始的索引,集合的第一個元素位於索引 0 處,最後一個元素位於索引 Count - 1 處。你可以通過確保訪問索引 Count - 1 處的最後一個元素來消除該錯誤,如下列代碼所示。
List < int > LBZHSs = [ 0 , 1 , 2 ]; try { for ( int z = 0 ; z <= LBZHSs . Count - 1 ; z++ ) { Console . WriteLine ( $"索引 {z}:{LBZHSs [ z ]}" ); } } catch ( ArgumentOutOfRangeException yc ) { Console . WriteLine ( yc . Message ); }
-
-
您正嘗試通過調用字符串操作方法來執行字符串操作,但起始索引在該字符串中不存在。
諸如 String . Compare、String . CompareOrdinal、String . IndexOf、String . IndexOfAny、String . Insert、String . LastIndexOf、String . LastIndexOfAny、String . Remove 或 String . Substring 等方法的重載允許你指定操作的起始索引,這些重載要求該索引是字符串內的有效位置。有效索引的範圍是從 0 到 String . Length - 1。
此 ArgumentOutOfRangeException 異常有四個常見原因:-
你正在根據 子字符串 在某個字符串中的位置來處理該字符串,但卻未能確定該 子字符串 是否真的存在。
以下示例提取一個雙詞短語中的第二個詞。如果該短語僅由一個詞組成,因而不包含嵌入的空格字符,那麼它會拋出一個 ArgumentOutOfRangeException 異常。出現這種情況是因為對 String . IndexOf ( 子字符串 ) 方法的調用返回 -1 以表示搜索失敗,而這個無效值隨後被傳遞給了 String . Substring ( 索引 ) 方法。Console . OutputEncoding = System . Text . Encoding . UTF8; String [ ] zfcCiZus = [ "ocean blue" , "concerned citizen" , "runOnPhrase" ]; foreach ( var zfcCiZu in zfcCiZus ) Console . WriteLine ( $"{zfcCiZu} 的第二個詞是:{FF獲取第二個詞 ( zfcCiZu )}" ); static string FF獲取第二個詞 ( string 詞組 ) { int zhs空格位置 = 詞組 . IndexOf ( ' ' ); try { if ( zhs空格位置 < 0 ) throw new ArgumentOutOfRangeException ( nameof ( 詞組 ) , "由於詞組中沒有空格(即一個詞),空格位置為 -1" ); return 詞組 [ zhs空格位置.. ] . Trim ( ); } catch ( ArgumentOutOfRangeException yc ) { return ( yc . Message ); } }要消除該異常,請在調用字符串操作方法之前驗證字符串搜索方法返回的值。
static string FF獲取第二個詞 ( string 詞組 ) { int zhs空格位置 = 詞組 . IndexOf ( ' ' ); string zfc第二個詞; if ( zhs空格位置 < 0 ) { return ""; } else { zfc第二個詞 = 詞組 [ zhs空格位置.. ]; if ( zfc第二個詞 . Trim ( ) . Length == 0 ) { return ""; } else return zfc第二個詞 . Trim ( ); } } -
你嘗試提取的子字符串超出了當前字符串的範圍。
提取子字符串的方法都要求你指定子字符串的起始位置,對於不會延續到字符串末尾的子字符串,還需要指定子字符串的字符數量。請注意,這並非子字符串中最後一個字符的索引。
在這種情況下,通常會拋出 ArgumentOutOfRangeException 異常,因為您錯誤地計算了子字符串中的字符數。如果您使用諸如 String . IndexOf 之類的搜索方法來確定子字符串的起始和結束位置:- 如果由 String . IndexOf 返回的結束位置處的字符要包含在子字符串中,則子字符串的結束位置由以下公式給出:
末索引 - 起始索引 + 1 - 如果 String . IndexOf 返回的結束位置處的字符要被排除在子字符串之外,則子字符串的結束位置由以下公式給出:
末索引 - 起始索引
以下示例定義了一個 FF查找單詞 方法,該方法使用 String . IndexOfAny ( Char [ ] , Int32 ) 方法來識別字符串中的空格字符和標點符號,並返回一個包含該字符串中找到的單詞的數組。
Console . OutputEncoding = System . Text . Encoding . UTF8; string zfc句子 = "These are my wife's clothes (silk jackets, sweaters, etc.). Have they been washed?"; Console . WriteLine ( $"在 ‘{zfc句子}’ 中的單詞:" ); foreach ( var CI in FF查找單詞 ( zfc句子 ) ) Console . WriteLine ( $" ‘{CI}’" ); static String [ ] FF查找單詞 ( string 句子 ) { int zhs起始 = 0 , zhs末尾 = 0; Char [ ] ZFs分隔符 = [ ' ' , '.' , ',' , ';' , ':' , '(' , ')' , '?' ]; List < string > LBZFCs詞 = [ ]; while ( zhs末尾 >= 0 ) { zhs末尾 = 句子 . IndexOfAny ( ZFs分隔符 , zhs起始 ); if ( zhs末尾 >= 0 ) { if ( zhs末尾 - zhs起始 > 0 ) LBZFCs詞 . Add ( 句子 [ zhs起始..zhs末尾 ] . Trim ( ) ); zhs起始 = zhs末尾 + 1; } else { if ( zhs起始 < 句子 . Length - 1 ) LBZFCs詞 . Add ( 句子 [ zhs起始.. ] . Trim ( ) ); } } return [ .. LBZFCs詞 ]; } - 如果由 String . IndexOf 返回的結束位置處的字符要包含在子字符串中,則子字符串的結束位置由以下公式給出:
-
-
你向一個僅接受正數和零作為參數的方法傳遞了負數,或者向一個僅接受正數作為參數的方法傳遞了負數或零。
例如,Array . CreateInstance ( Type , Int32 , Int32 ) 方法要求指定二維數組各維度中的元素數量;每個維度的有效值範圍可以是 0 到 Int32 . MaxValue。但由於下面的示例中維度參數的值為負數,該方法會引發 ArgumentOutOfRangeException 異常。Console . OutputEncoding = System . Text . Encoding . UTF8; int zhs維度1 = 10; int zhs維度2 = -1; try { Array SZ字符串 = Array . CreateInstance ( typeof ( string ) , zhs維度1 , zhs維度2 ); } catch ( ArgumentOutOfRangeException yc ) { if ( yc . ActualValue != null ) Console . WriteLine ( $"{yc . ActualValue} 是一個無效的 {yc . ParamName} 值:" ); Console . WriteLine ( yc . Message ); }要糾正該錯誤,請確保無效參數的值為非負數。您可以通過提供有效值來實現,如下代碼片段所示。
int zhs維度1 = 10; int zhs維度2 = 10;你也可以驗證輸入,如果輸入無效,則採取一些措施。以下代碼片段會顯示錯誤消息,而不是調用該方法。
-
在多線程應用程序中,或者在具有異步執行任務並更新數組或集合的應用程序中,會存在競態條件。
以下示例使用 List < T > 對象來填充 LEI洲 對象的集合。如果該示例在集合完全填充之前嘗試顯示集合中的七個項,它將拋出 ArgumentOutOfRangeException。// 設置控制枱輸出編碼為 UTF-8,支持中文等 Unicode 字符顯示 Console . OutputEncoding = System . Text . Encoding . UTF8; // 創建一個空的洲(LEI洲)列表,使用新的集合表達式(C# 12+) List < LEI洲 > LB大洲 = [ ]; // 初始化消息字符串,用於記錄線程處理信息 string? zfc線程處理信息 = ""; // 創建線程列表,用於存儲所有線程引用,以便後續等待它們完成 List < Thread > XianChengs = [ ]; // 定義七大洲的名稱數組,使用新的數組表達式(C# 12+) String [ ] zfc洲名s = [ "北美洲" , "大洋洲" , "非洲" , "南極洲" , "南美洲" , "歐洲" , "亞洲" ]; // 創建鎖對象,用於保護共享資源(LB大洲 列表和 zfc線程處理信息)的併發訪問避免多個線程同時修改共享數據導致的數據不一致問題 object dx鎖定 = new ( ); // 使用線程填充列表,遍歷每個大洲名稱,創建並啓動對應的線程 foreach ( string ming in zfc洲名s ) { // 創建當前名稱的局部副本,避免閉包問題 // 如果沒有這個副本,所有 lambda 表達式會共享同一個 ming 變量 string zfc當前名 = ming; // 創建新線程,使用 lambda 表達式定義線程要執行的方法 // lambda 表達式捕獲了zfc當前名、LB大洲、zfc線程處理信息 和 dx鎖定 Thread? XianCheng = new ( ( ) => FF添加洲 ( zfc當前名 , LB大洲 , ref zfc線程處理信息 , dx鎖定 ) ); // 將線程添加到線程列表,便於後續管理 XianChengs . Add ( XianCheng ); // 啓動線程,開始異步執行 FF添加洲 方法 XianCheng . Start ( ); } // 注意:這裏輸出 zfc線程處理信息 可能為 null、Empty 或不完整!因為線程還在執行,zfc線程處理信息 可能還沒被完全填充 Console . WriteLine ( zfc線程處理信息 ); Console . WriteLine ( ); // 等待所有線程完成,這是避免 ArgumentOutOfRangeException 的關鍵步驟! // 使用 Join ( ) 方法等待每個線程執行完畢,如果沒有這個等待,主線程會立即繼續執行,而子線程可能還沒完成 foreach ( Thread xc in XianChengs ) xc . Join ( ); // 等待當前線程完成,阻塞主線程直到線程結束 // 現在可以安全訪問列表! // 因為所有線程都已通過 Join ( ) 完成,LB大洲 列表已被完全填充。這裏使用 zfc洲名s . Length 作為循環條件是安全的 for ( int suoyin = 0 ; suoyin < zfc洲名s . Length ; suoyin++ ) { // 現在這裏是安全的,不會拋出 ArgumentOutOfRangeException // 因為:1. 所有線程已完成(通過 Join ( ) 確保) // 2. 每個線程都向列表添加了一個元素 // 3. 所以 LB洲名s . Count == zfc洲名s . Length LEI洲? Zhou = LB大洲 [ suoyin ]; // 輸出大洲信息 Console . WriteLine ( $"{Zhou . 大洲名}:面積 → {Zhou . 面積},人口 → {Zhou . 人口}" ); } // 線程執行的方法定義 // 參數説明: // 洲名:大洲名稱 // LB大洲:要填充的列表(共享資源) // zfc線程處理信息:日誌消息(共享資源) // dx鎖定:用於同步的鎖對象 static void FF添加洲 ( string 洲名 , List < LEI洲 > 洲列表 , ref string 線程信息 , object 鎖定對象 ) { // 創建隨機數對象 Random SJS = new ( ); // 使用 lock 保護共享資源 // lock 語句確保同一時間只有一個線程能執行這個代碼塊,這防止了多個線程同時修改 LB大洲 和 zfc線程處理信息 導致的數據競爭 lock ( 鎖定對象 ) { // 添加處理日誌 線程信息 += $"添加 ‘{洲名}’ 到列表中。\n"; // 創建大洲對象 LEI洲 Zhou = new ( ) { 大洲名 = 洲名 }; // 模擬數據檢索:生成隨機的面積和人口 Zhou . 面積 = SJS . Next ( 1000 , 10000 ); // 面積在 1,000 ~ 9,999 之間 Zhou . 人口 = SJS . Next ( 1000000 , 10000000 ); // 人口在 1,000,000 ~ 9,999,999 之間 // 向共享列表添加元素 // 由於在 lock 塊內,這個操作是線程安全的,不會發生兩個線程同時 Add 導致的數據損壞 洲列表 . Add ( Zhou ); } Thread . Sleep ( SJS . Next ( 10 , 100 ) ); // 休眠 10 ~ 99 毫秒,模擬數據處理時間 } // 大洲類定義 public class LEI洲 { // 大洲名稱 public string? 大洲名 { get; set; } // 人口數量 public int 人口 { get; set; } // 面積 public Decimal 面積 { get; set; } }記住這一段:
// 等待所有線程完成,這是避免 ArgumentOutOfRangeException 的關鍵步驟! // 使用 Join ( ) 方法等待每個線程執行完畢,如果沒有這個等待,主線程會立即繼續執行,而子線程可能還沒完成 foreach ( Thread xc in XianChengs ) xc . Join ( ); // 等待當前線程完成,阻塞主線程直到線程結束當你註釋掉這一段時,有兩個資源同時會被多個線程訪問:
- LB大洲。其 List < T > . Add 方法會從多個線程調用。此外,主線程在迭代其成員時,會假設該集合已完全填充了七個元素。
- zfc線程處理信息。它是由多個線程拼接而成的。
因此當主線程執行時,子線程幾乎可以肯定尚未結束。即 LB大洲 列表中尚未有 7 個元素,所以:
for ( int suoyin = 0 ; suoyin < zfc洲名s . Length ; suoyin++ ) { LEI洲? Zhou = LB大洲 [ suoyin ]; ……一定會拋出 ArgumentOutOfRangeException。
要糾正此錯誤,請確保以線程安全的方式訪問共享狀態,如下所示。
如果你的應用程序使用數組或集合對象,請考慮使用線程安全的集合類,例如 System . Collections . Concurrent 命名空間中的類型或 System . Collections . Immutable 帶外版本中的類型。
確保共享狀態(即可以被多個線程訪問的資源)以線程安全的方式被訪問,這樣同一時間只有一個線程能獨佔訪問這些資源。有大量類可用於同步資源訪問,例如 CountdownEvent、Interlocked、Monitor 和 Mutex。
以下示例解決了上一個示例中的 ArgumentOutOfRangeException(參數超出範圍異常)和其他問題。它用 ConcurrentBag < T > 對象替換了 List < T > 對象,以確保對集合的訪問是線程安全的;使用 CountdownEvent(倒計時事件)對象確保應用程序線程僅在其他線程執行完畢後才繼續;並使用鎖來確保一次只有一個線程可以訪問 zfc線程處理信息 變量。using System . Collections . Concurrent; using System . Text; // 設置控制枱輸出編碼為 UTF-8,支持中文等 Unicode 字符顯示 Console . OutputEncoding = System . Text . Encoding . UTF8; // 使用 ConcurrentBag 存儲大洲對象,它是線程安全的 ConcurrentBag < LEI洲 > LB大洲 = [ ]; // 使用 CountdownEvent 進行線程同步 CountdownEvent? jsq倒計數器; // 處理日誌 StringBuilder sb日誌構建器 = new ( ); object suo日誌 = new ( ); // 大洲名稱數組 string [ ] ZFCs大洲名稱列表 = [ "亞洲" , "非洲" , "北美洲" , "南美洲" , "南極洲" , "歐洲" , "大洋洲" ]; Console . OutputEncoding = System . Text . Encoding . UTF8; Console . WriteLine ( "🌍 大洲數據處理程序開始運行\n" ); // 創建計數器,初始值為大洲數量 jsq倒計數器 = new CountdownEvent ( ZFCs大洲名稱列表 . Length ); // 為每個大洲創建處理線程 foreach ( string 洲名 in ZFCs大洲名稱列表 ) { // 啓動新線程處理該大洲 Thread 處理線程 = new ( 處理單個大洲 ); 處理線程 . Start ( 洲名 ); Console . WriteLine ( $"📋 已啓動 {洲名} 處理線程" ); } Console . WriteLine ( $"\n⏳ 共有 {ZFCs大洲名稱列表 . Length} 個線程在處理,等待完成……\n" ); // 等待所有線程處理完成 jsq倒計數器 . Wait ( ); Console . WriteLine ( "✅ 所有數據處理完成!\n" ); // 輸出處理日誌 Console . WriteLine ( "📋 處理日誌:" ); Console . WriteLine ( sb日誌構建器 . ToString ( ) ); // 獲取處理結果數組 LEI洲 [ ] 結果數組 = [ .. LB大洲 ]; Console . WriteLine ( "\n📊 大洲統計信息:" ); Console . WriteLine ( "==============================================================" ); Console . WriteLine ( $"{"大洲" + ":",-8}\t{"人口",16}\t{"面積",16}" ); Console . WriteLine ( "--------------------------------------------------------------" ); // 輸出每個大洲的數據 for ( int 序號 = 0 ; 序號 < 結果數組 . Length ; 序號++ ) { LEI洲 當前大洲 = 結果數組[序號]; Console . WriteLine ( $"{當前大洲 . 名稱 + ":",-8}\t{當前大洲 . 人口數,20:N0}\t{當前大洲 . 面積數,20:N0}" ); } Console . WriteLine ( "==============================================================\n" ); Console . WriteLine ( $"📈 共處理 {結果數組 . Length} 個大洲數據" ); // 線程處理方法:處理單個大洲 void 處理單個大洲 ( object? 大洲名 ) { // 獲取大洲名稱 string? 洲名 = 大洲名? . ToString ( ); if ( string . IsNullOrWhiteSpace ( 洲名 ) ) { Console . WriteLine ( "⚠️ 警告:收到空的洲名參數" ); return; } // 生成隨機數據 Random SJS = new( Guid . NewGuid ( ) . GetHashCode ( ) ); // 模擬數據處理時間 int zhs處理時間 = SJS . Next ( 20 , 100 ); Thread . Sleep ( zhs處理時間 ); // 創建大洲數據對象 LEI洲 Zhou = new ( ) { 名稱 = 洲名, 人口數 = SJS . Next ( 1000000 , 50000000 ), // 100 萬 ~ 5000 萬人 面積數 = SJS . Next ( 100000 , 10000000 ) // 10 萬 ~ 1000 萬平方公里 }; // 添加到線程安全列表 LB大洲 . Add ( Zhou ); // 記錄處理日誌(需要線程安全) lock ( sb日誌構建器 ) { sb日誌構建器 . AppendLine ( $"✅ 已處理:{洲名}(耗時:{zhs處理時間} 毫秒)\n" ); } // 通知計數器完成一個任務 jsq倒計數器? . Signal ( ); Console . WriteLine ( $" 線程 {Environment . CurrentManagedThreadId} 完成:{洲名}" ); } /// <summary> /// 模擬的各大洲 /// </summary> public class LEI洲 { public string? 名稱 { get; set; } // 大洲名稱 public int 人口數 { get; set; } // 人口數量 public decimal 面積數 { get; set; } // 面積 }構造函數
重載
名稱 描述 ArgumentOutOfRangeException ( ) 初始化 ArgumentOutOfRangeException 類的新實例 ArgumentOutOfRangeException ( String 參數名稱 ) 使用導致此異常的參數的名稱來初始化新實例 ArgumentOutOfRangeException ( String 異常信息 , Exception 實際異常 ) 使用指定的錯誤消息和內部異常初始化新實例 ArgumentOutOfRangeException ( String 參數名稱 , String 異常信息 ) 使用參數名和指定的錯誤消息初始化新實例 ArgumentOutOfRangeException ( String 參數名稱 , Object 參數值 , String 異常信息 ) 使用參數名、參數的實際值和指定的錯誤消息初始化新實例 參數
參數 類型 描述 參數名稱 string 導致此異常的參數名稱 異常信息 string 異常的解釋信息 實際異常 Exception 作為當前異常原因的異常,或者如果未指定內部異常,則為 null 引用(在 Visual Basic 中為 Nothing) 參數值 Object 導致此異常的參數值 備註
無參數
將新實例的 Message 屬性初始化為系統提供的描述錯誤的消息,例如 “"Nonnegative number required.”。此消息會考慮當前的系統區域性。
下表顯示了 ArgumentOutOfRangeException 實例的初始屬性值。
| 屬性 | 值 |
|---|---|
| InnerException | null 引用(Visual Basic 中為 Nothing) |
| Message | 本地化的錯誤消息字符串 |
參數名稱 參數
將新實例的 Message 屬性初始化為系統提供的描述錯誤的消息,例如 “"Nonnegative number required.”。此消息會考慮當前的系統區域性。使用 參數名稱 初始化 ParamName 屬性。
下表顯示了 ArgumentOutOfRangeException 實例的初始屬性值。
| 屬性 | 值 |
|---|---|
| InnerException | null 引用(Visual Basic 中為 Nothing) |
| Message | 本地化的錯誤消息字符串 |
| ParamName | 參數名稱 |
參數名稱 和 實際異常 參數
將新實例的 Message 屬性初始化為 異常信息 提供的描述錯誤的消息。並使用 實際異常 初始化 InnerException 屬性。
下表顯示了 ArgumentOutOfRangeException 實例的初始屬性值。
| 屬性 | 值 |
|---|---|
| InnerException | 實際異常 |
| Message | 本地化的錯誤消息字符串 |
| ParamName | 參數名稱 |
參數名稱 和 異常信息 參數
將新實例的 Message 屬性初始化為 異常信息 提供的描述錯誤的消息。並使用 參數名稱 初始化 ParamName 屬性。
下表顯示了 ArgumentOutOfRangeException 實例的初始屬性值。
| 屬性 | 值 |
|---|---|
| InnerException | null 引用(Visual Basic 中為 Nothing) |
| Message | 異常信息 |
| ParamName | 參數名稱 |
參數名稱、參數值 和 異常信息 參數
將新實例的 Message 屬性初始化為 異常信息 提供的描述錯誤的消息。使用 參數名稱 初始化 ParamName 屬性。使用 參數值 參數初始化 ActualValue 屬性。
.NET類庫中不使用 ActualValue 參數。不過,應用程序可以使用 ActualValue 屬性來獲取可用的參數值。
ActualValue 參數包含傳遞給該方法的無效值,正是這個值導致拋出此異常。該值存儲在 ActualValue 屬性中,其字符串表示形式會附加到 Message 屬性所包含的消息字符串中。
下表顯示了 ArgumentOutOfRangeException 實例的初始屬性值。
| 屬性 | 值 |
|---|---|
| ActualValue | 參數值 |
| InnerException | null 引用(Visual Basic 中為 Nothing) |
| Message | 異常信息 |
| ParamName | 參數名稱 |
示例
以下示例展示了創建一個具有 ActualValue、Message 和 ParamName 屬性的 ArgumentOutOfRangeException:
FF處理數組 ( 3 );
static void FF處理數組 ( int 索引 )
{
int [ ] ZHSs = [ 3 , 6 , 9 ];
for ( int i = 0 ; i <= 索引 ; i++ )
{
try
{
if ( i < ZHSs . Length )
{ Console . WriteLine ( $"{ZHSs [ i ]}" ); }
else
{ throw new ArgumentOutOfRangeException ( nameof ( 索引 ) , i , "索引不能大於等於數組的長度(Length)" ); }
}
catch ( ArgumentOutOfRangeException yc )
{
Console . WriteLine ( yc . Message );
}
}
}
屬性
ActualValue
獲取導致此異常的參數值。
public virtual object? ActualValue { get; }
屬性值
| 類型 | 説明 |
|---|---|
| Object | 導致當前 Exception 的參數值 |
備註
使用此屬性來檢索無效參數。
ActualValue 屬性返回傳遞給構造函數的值,如果未提供值,則返回 null。
ActualValue 屬性在對象構造時被賦值。如果 ActualValue 屬性值不為 null,則該值的字符串表示形式會被追加到 Message 屬性所保存的消息字符串中。例如構造函數示例中,下列消息被追加到 Message 中:
Actual value was 3.
.NET 類庫中不使用 ActualValue 屬性。在 .NET 類庫拋出的所有 ArgumentOutOfRangeException 對象中,它都帶有 null 值。提供 ActualValue 屬性是為了讓應用程序能夠使用可用的參數值。
此屬性為只讀,僅應在需要自定義值的內容或格式時進行重寫。
Message
獲取錯誤消息和無效參數值的字符串表示形式,如果參數值為 null,則僅獲取錯誤消息。
public override string Message { get; }
屬性值
| 類型 | 異常信息 | 參數值 | 註解 |
|---|---|---|---|
| String | null | 默認的 Message 字符串 | |
| 異常信息 | null | 異常信息 | |
| 異常信息 | 參數值 | 異常信息\n參數值 |
備註
此屬性重寫 Message。
錯誤消息應描述導致此異常的參數的預期值。錯誤消息應進行本地化處理。
方法
當參數值(或者包括比較值)符合某個條件時,拋出 ArgumentOutOfRangeException。
一元ThrowIf(與固定基準值 0 比較)
| 方法 | 描述 | 等效代碼 | 拋出條件 |
|---|---|---|---|
| ThrowIfNegative ( 參數 ) | 如果 參數 為負數則拋出異常 | if ( 參數 < 0 ) throw new ArgumentOutOfRangeException ( …… ) | 參數 < 0 |
| ThrowIfNegativeOrZero ( 參數 ) | 如果 參數 為負數或零則拋出異常 | if ( 參數 <= 0 ) throw new ArgumentOutOfRangeException ( …… ) | 參數 ≤ 0 |
| ThrowIfZero ( 參數 ) | 如果 參數 為零則拋出異常 | if ( 參數 == 0 ) throw new ArgumentOutOfRangeException ( …… ) | 參數 = 0 |
二元ThrowIf(與任意基準值比較)
| 方法 | 描述 | 等效代碼 | 拋出條件 |
|---|---|---|---|
| ThrowIfEqual ( 參數 , 比較值 ) | 如果 參數 等於 比較值 則拋出異常 | if ( 參數 == 比較值 ) throw new ArgumentOutOfRangeException ( …… ) | 參數 = 比較值 |
| ThrowIfNotEqual ( 參數 , 比較值 ) | 如果 參數 不等於 比較值 則拋出異常 | if ( 參數 != 比較值 ) throw new ArgumentOutOfRangeException ( …… ) | 參數 ≠ 比較值 |
| ThrowIfGreaterThan ( 參數 , 比較值 ) | 如果 參數 大於 比較值 則拋出異常 | if ( 參數 > 比較值 ) throw new ArgumentOutOfRangeException ( …… ) | 參數 > 比較值 |
| ThrowIfGreaterThanOrEqual ( 參數 , 比較值 ) | 如果 參數 大於等於 比較值 則拋出異常 | if ( 參數 >= 比較值 ) throw new ArgumentOutOfRangeException ( …… ) | 參數 >= 比較值 |
| ThrowIfLessThan ( 參數 , 比較值 ) | 如果 參數 小於 比較值 則拋出異常 | if ( 參數 < 比較值 ) throw new ArgumentOutOfRangeException ( …… ) | 參數 < 比較值 |
| ThrowIfLessThanOrEqual ( 參數 , 比較值 ) | 如果 參數 小於等於 比較值 則拋出異常 | if ( 參數 <= 比較值 ) throw new ArgumentOutOfRangeException ( …… ) | 參數 <= 比較值 |
參數
| 參數 | 類型 | 註解 |
|---|---|---|
| 參數 | 值類型或任意類型 | 一元的 ThrowIf 其參數必須實現 IComparisonOperators < T , T , bool > 和 INumberBase < T > 接口
二元的 ThrowIf 其參數必須實現 IComparable < T > 接口 參數 值與 0(一元ThrowIf)或 比較值(二元ThrowIf)的比較結果決定是否拋出 ArgumentOutOfRangeException |
| 比較值 | 任意類型 | 必須與 參數 類型相同(包括實現同樣的 IComparable < T > 接口) |