如何修复Between方法以支持多种数值类型混合及dynamic参数探讨
修复Between方法并简化实现方案
问题分析
原Between方法处理int、decimal、double及对应可空类型的混合参数时(比如Between((int)1, (decimal)1, (decimal)2)),会抛出"Cannot cast integer to decimal"异常——原因是直接用(decimal)value这类硬强制转换对不同数值类型不兼容,int无法直接强制转为decimal,需显式转换而非强制转换。同时代码存在其他小问题:DateOnly分支的null处理错误,字符串/char分支的条件重复。
修复方案(不使用dynamic)
针对数值类型,通过IConvertible接口统一转换为decimal,避免硬强制转换的问题;同时修正其他分支的错误:
static bool Between(object value, object low, object high) { if (value == null && low == null && high == null) return false; // 处理数值类型(int/decimal/double及可空类型) if (value is IConvertible numVal || low is IConvertible numLow || high is IConvertible numHigh) { // 先处理可空类型的null值,再转换为decimal decimal val = numVal?.ToDecimal(null) ?? 0; decimal lower = numLow?.ToDecimal(null) ?? 0; decimal upper = numHigh?.ToDecimal(null) ?? 0; return val >= lower && val <= upper; } // 处理DateOnly及可空类型 if (value is DateOnly? dateVal || low is DateOnly? dateLow || high is DateOnly? dateHigh) { DateOnly val = dateVal ?? DateOnly.MinValue; DateOnly lower = dateLow ?? DateOnly.MinValue; DateOnly upper = dateHigh ?? DateOnly.MinValue; return val >= lower && val <= upper; } // 处理字符串、char及可空char类型 if (value is string || value is char? || low is string || low is char? || high is string || high is char?) { string valStr = value?.ToString() ?? string.Empty; string lowStr = low?.ToString() ?? string.Empty; string highStr = high?.ToString() ?? string.Empty; return valStr.CompareTo(lowStr) >= 0 && valStr.CompareTo(highStr) <= 0; } throw new ArgumentException("Incompatible argument types"); }
使用dynamic简化实现
在ASP.NET 8对应的最新版C#中,使用dynamic参数可以让运行时自动处理类型转换和比较逻辑,大幅简化代码:
基础版dynamic实现
static bool Between(dynamic value, dynamic low, dynamic high) { if (value == null && low == null && high == null) return false; try { // 运行时自动处理类型转换和比较 return value >= low && value <= high; } catch (InvalidOperationException) { throw new ArgumentException("Incompatible argument types"); } }
兼容null默认值的dynamic实现
如果需要自动将null替换为对应类型的默认值,可补充逻辑:
static bool Between(dynamic value, dynamic low, dynamic high) { if (value == null && low == null && high == null) return false; // 处理null值,替换为对应类型的默认值 dynamic val = value ?? GetDefaultValue(value?.GetType() ?? low?.GetType() ?? high.GetType()); dynamic lower = low ?? GetDefaultValue(low?.GetType() ?? value?.GetType() ?? high.GetType()); dynamic upper = high ?? GetDefaultValue(high?.GetType() ?? value?.GetType() ?? low.GetType()); try { return val >= lower && val <= upper; } catch (Exception) { throw new ArgumentException("Incompatible argument types"); } } private static dynamic GetDefaultValue(Type type) { if (type == null) return null; return type.IsValueType ? Activator.CreateInstance(type) : null; }
dynamic方案的注意事项
- 运行时类型检查:传入无法比较的类型(比如string和int)会抛出异常,需捕获并转换为自定义ArgumentException。
- 性能影响:dynamic会带来轻微的运行时开销,但多数业务场景下可忽略。
- 可空类型支持:基础版不自动处理null与数值的比较,需额外逻辑补充默认值替换。
关键修正点
- 数值类型:用
IConvertible.ToDecimal替代硬强制转换,支持所有数值类型及可空类型的转换。 - DateOnly分支:修正
value ?? 0的错误,改为DateOnly.MinValue。 - 字符串/char分支:简化类型判断,用
ToString()统一处理char和string类型。 - dynamic方案:利用C#动态类型特性,自动处理类型转换和比较,减少冗余代码。
内容的提问来源于stack exchange,提问作者Andrus
相关产品推荐
相关产品推荐

