C#泛型匹配抽象类类型失败及协变逆变简化方案咨询
问题分析与解决方案
原代码失败原因
你的第一段代码中,if (handler is Handler<IRequest<T>, T> h)的类型检查始终失败,核心原因是:
- 泛型类不支持协变或逆变,
GetAgeHandler是Handler<GetAge, int>的实例,而Handler<GetAge, int>和Handler<IRequest<int>, int>是完全独立的封闭构造类型,无法互相转换。 - 类型检查不通过后直接返回
default,导致预期的20无法输出。
利用协变/逆变简化实现
不需要额外添加多层接口,只需定义一个支持逆变的泛型接口即可解决问题。泛型接口可以通过in和out关键字实现类型协变/逆变,而类不支持这一特性。
简化后的代码
void Main() { var requestHandler = new RequestHandler(); var result = requestHandler.Handle(new GetAge()); Console.WriteLine(result); // 输出20 } public interface IRequest<T> { } public class GetAge : IRequest<int> { } // 定义支持逆变的请求处理器接口: // - in TRequest:逆变参数,允许用子类请求类型的处理器处理父类请求类型 // - out TResponse:协变参数,允许返回子类响应类型的处理器适配父类响应类型 public interface IHandler<in TRequest, out TResponse> where TRequest : IRequest<TResponse> { TResponse Handle(TRequest request); } // 抽象基类封装类型转换逻辑,子类只需实现具体业务 public abstract class HandlerBase<TRequest, TResponse> : IHandler<TRequest, TResponse> where TRequest : IRequest<TResponse> { public TResponse Handle(TRequest request) { return HandleRequest(request); } protected abstract TResponse HandleRequest(TRequest request); } public class GetAgeHandler : HandlerBase<GetAge, int> { protected override int HandleRequest(GetAge request) { return 20; } } public class RequestHandler { private readonly Dictionary<Type, object> _handlers = new() { [typeof(GetAge)] = new GetAgeHandler() }; public TResponse Handle<TResponse>(IRequest<TResponse> request) { var requestType = request.GetType(); if (_handlers.TryGetValue(requestType, out var handler)) { // 利用逆变特性,将HandlerBase<GetAge, int>转换为IHandler<IRequest<TResponse>, TResponse> if (handler is IHandler<IRequest<TResponse>, TResponse> typedHandler) { return typedHandler.Handle((IRequest<TResponse>)request); } } return default; } }
核心原理
- 逆变参数
in TRequest:当TRequest标记为in时,IHandler<GetAge, int>可以安全地转换为IHandler<IRequest<int>, int>,因为GetAge是IRequest<int>的子类,处理器能够接受更通用的IRequest<int>类型作为输入。 - 这个特性绕过了泛型类的类型限制,让你无需额外定义
IHandler<TResponse>这类中间接口,就能完成类型匹配与调用。
扩展支持多请求类型
如果需要添加GetName这类其他请求,只需新增请求类、处理器类,并在字典中注册即可,逻辑完全复用:
public class GetName : IRequest<string> { } public class GetNameHandler : HandlerBase<GetName, string> { protected override string HandleRequest(GetName request) { return "Foo"; } } // 在RequestHandler的_handlers中添加: [typeof(GetName)] = new GetNameHandler()
内容的提问来源于stack exchange,提问作者Marat K
相关产品推荐
相关产品推荐

