能否在泛型表达式中向自定义异常构造函数传递参数?
泛型自定义异常抛出的实现问题
直接回答你的问题
不行。当前泛型约束中的new()仅保证TException类型存在无参构造函数,无法直接通过new TException(message, Exception)的方式调用带参构造函数。
现有代码的问题
你的ExceptionThrower<TException>类中,目前只是返回了无参构造的TException实例,没有传入从数据库获取的异常消息和内部异常,完全不符合需求。
可行的替代方案
方案一:利用反射实例化带参构造的异常
通过反射获取TException中接收(string, Exception)参数的构造函数,再创建实例:
public static class ExceptionThrower<TException> where TException : Exception, ICustomException { public static async Task<TException> ThrowException(ErrorCode errorCode, Exception exception) { using var ctx = new ExceptionContext(); var messageEntity = await ctx.ExceptionMessages .Where(x => x.ErrorCode == (int)errorCode) .FirstOrDefaultAsync(); var errorMessage = messageEntity?.Message ?? "未知错误"; // 获取目标构造函数 var constructor = typeof(TException).GetConstructor( new[] { typeof(string), typeof(Exception) }); if (constructor == null) { throw new InvalidOperationException( $"类型 {typeof(TException).Name} 未定义接收(string, Exception)参数的构造函数"); } // 实例化并返回异常 return (TException)constructor.Invoke(new object[] { errorMessage, exception }); } }
注意:反射会带来一定性能开销,若你的场景是高频异常抛出,需要权衡性能影响。
方案二:通过自定义接口的初始化方法设置参数
修改ICustomException接口,添加初始化方法,让自定义异常实现该方法来设置消息和内部异常:
- 定义接口:
public interface ICustomException { void Initialize(string message, Exception innerException); }
- 修改自定义异常实现:
public class DbAddException : Exception, ICustomException { public DbAddException() { } public DbAddException(string message) : base(message) { } public DbAddException(string message, Exception innerException) : base(message, innerException) { } public void Initialize(string message, Exception innerException) { // 通过反射修改Exception的私有字段,因为Message和InnerException是只读属性 var messageField = typeof(Exception).GetField("_message", BindingFlags.Instance | BindingFlags.NonPublic); var innerExField = typeof(Exception).GetField("_innerException", BindingFlags.Instance | BindingFlags.NonPublic); messageField?.SetValue(this, message); innerExField?.SetValue(this, innerException); } }
- 更新
ExceptionThrower:
public static class ExceptionThrower<TException> where TException : Exception, ICustomException, new() { public static async Task<TException> ThrowException(ErrorCode errorCode, Exception exception) { using var ctx = new ExceptionContext(); var messageEntity = await ctx.ExceptionMessages .Where(x => x.ErrorCode == (int)errorCode) .FirstOrDefaultAsync(); var errorMessage = messageEntity?.Message ?? "未知错误"; var exceptionInstance = new TException(); exceptionInstance.Initialize(errorMessage, exception); return exceptionInstance; } }
方案三:通过委托传入异常构造逻辑
移除new()约束,让调用方传入一个构造委托,直接指定异常的创建方式,这是最灵活且无反射开销的方案:
public static class ExceptionThrower<TException> where TException : Exception, ICustomException { public static async Task<TException> ThrowException( ErrorCode errorCode, Exception exception, Func<string, Exception, TException> exceptionFactory) { using var ctx = new ExceptionContext(); var messageEntity = await ctx.ExceptionMessages .Where(x => x.ErrorCode == (int)errorCode) .FirstOrDefaultAsync(); var errorMessage = messageEntity?.Message ?? "未知错误"; return exceptionFactory(errorMessage, exception); } }
调用示例:
await ExceptionThrower<DbAddException>.ThrowException( ErrorCode.DbAddError, innerException, (msg, inner) => new DbAddException(msg, inner));
内容的提问来源于stack exchange,提问作者Stick
相关产品推荐
相关产品推荐

