在反射、序列化、模型綁定、動態代碼生成等場景中,經常需要判斷 `Type` 對象是否代表數值類型 (int, double, decimal 等)。.NET Framework **未提供** `Type.IsNumeric` 內置屬性,開發者需自行實現。
public static bool IsNumericInterface(this Type type)
{
if (type == null) throw new ArgumentNullException(nameof(type));
// 1. 必須是值類型 (struct) 且非 enum
if (!type.IsValueType || type.IsEnum) return false;
// 2. 解包 Nullable
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
type = type.GetGenericArguments()[0];
// 3. 核心判斷:實現 IFormattable 且非 Char/Boolean/DateTime/Guid
// 注意:Char 也實現 IFormattable,需排除
if (type == typeof(char) || type == typeof(bool) || type == typeof(DateTime) || type == typeof(Guid))
return false;
return typeof(IFormattable).IsAssignableFrom(type);
}
// BenchmarkDotNet 結果 (示意) | Method | Mean (ns) | Allocated | |-------------------|----------:|----------:| | IsNumericEnum | 12.3 | 0 B | | IsNumericInterface| 45.7 | 24 B | (反射 GetInterfaces 分配數組) | IsNumericModern | 3.1 | 0 B | (TypeCode 查表最快)
應用場景示例
總結建議
- 現代項目 (.NET Core 3.1+ / .NET 5+):優先使用 TypeCode 方案 (`IsNumericModern`),性能最佳、代碼最少、語義清晰。
- 舊項目 (.NET Framework 4.x):`Type.GetTypeCode` 同樣可用,推薦作為首選。
- 需支持自定義數值類型:結合接口特徵法 (`IFormattable` + 排除列表) 或 .NET 7+ `INumber
` 接口。 - 避免:`GetInterfaces().Any()` 反射分配數組,高頻調用有 GC 壓力。