C#扩展方法如何获取调用方属性名以用于异常信息输出?
解决方案
方案1:使用CallerArgumentExpression特性(推荐,C# 10及以上版本支持)
这是最简单的实现方案,不需要修改任何现有调用代码,编译器会自动填充属性调用的表达式文本:
修改你的扩展方法,新增一个带[CallerArgumentExpression]特性的参数即可:
/// <summary> /// 把字符串转换为T类型的值 /// 可配置转换失败或得到默认值时抛出异常 /// </summary> /// <typeparam name="T">要转换的目标类型</typeparam> /// <param name="value">待转换的字符串值</param> /// <param name="throwOnDefault">设置为true时,转换失败或得到默认值会抛出异常</param> /// <param name="methodName">调用方方法名,编译器自动填充</param> /// <param name="propertyPath">调用方传入value的表达式,编译器自动填充</param> /// <returns>转换后的值</returns> /// <exception cref="NotSupportedException">字符串无法转换为目标类型时抛出</exception> /// <exception cref="Exception">转换后得到目标类型默认值时抛出</exception> public static T ParseOrDefault<T>(this string value, bool throwOnDefault = false, [CallerMemberName]string methodName = "", [CallerArgumentExpression(nameof(value))]string propertyPath = "") { if (Nullable.GetUnderlyingType(typeof(T)) == null && string.IsNullOrWhiteSpace(value)) // 注意:ArgumentNullException第一个参数是异常参数名,不要直接传value throw new ArgumentNullException(propertyPath, $"{methodName} : value of {propertyPath} is null"); System.ComponentModel.TypeConverter converter = System.ComponentModel.TypeDescriptor.GetConverter(typeof(T)); try { var converted = (T)converter.ConvertFromString(null, System.Globalization.CultureInfo.InvariantCulture, value); if (converted is ValueType val) { var defaultValue = Activator.CreateInstance(val.GetType()); return !val.Equals(defaultValue) ? converted : throw new Exception($"{methodName} : Converted value of {propertyPath} is default value"); } return converted; } catch (Exception) { if (throwOnDefault) throw; return default; } }
调用方式和你原有代码完全一致,无需额外传参:
public void SomeMethod (RequestModel request) { Dto dto = new() { intProperty = request.IntValue.ParseOrDefault<int>(), guidProperty = request.GuidValue.ParseOrDefault<Guid>() } }
此时如果request.IntValue为空,抛出的异常信息会自动变成SomeMethod : value of request.IntValue is null,完全符合你的需求。
方案2:C# 10以下版本兼容方案
如果你的项目使用的C#版本低于10,无法使用CallerArgumentExpression特性,可以选择以下两种实现方式:
- 手动传入属性名:调用时显式传入
nameof参数,示例:intProperty = request.IntValue.ParseOrDefault<int>(propertyName: nameof(request.IntValue)) - 基于表达式树封装扩展方法:无需手动传参,但运行时会有少量性能损耗,适合对性能要求不高的场景。
内容的提问来源于stack exchange,提问作者Trickster91
相关产品推荐
相关产品推荐

