正如其他人所提到的 - 没有办法做到“你正在做的方式”......
a) 你需要contravariance
- 为了Add
工作
b) 你需要covariance
能够upcast
从IResponseHandler<TResponse>
到IResponseHandler<IResponse>
(你也有另一个编译问题,返回out
到不同类型的列表,这两种方式都不能工作)......
对于一个解决方案 -如果这满足您trick
的需求,您可以将它投入工作。contract
当您失去一些支持时,这更像是一个“实践示例” - 但取决于您需要什么......
interface IResponse { }
interface IResponseHandler<out TResponse>
where TResponse : class, IResponse
{
// add 'read-only' (simplified) properties only - that support 'covariance' - meaning no 'input parameters' of T etc.
// void Handle(TResponse response);
}
abstract class ResponseHandler<TResponse> : IResponseHandler<TResponse>
where TResponse : class, IResponse
{
public abstract void Handle(TResponse response);
}
class TestHandler
{
private static Dictionary<Type, List<IResponseHandler<IResponse>>> _handlerMap = new Dictionary<Type,List<IResponseHandler<IResponse>>>();
public static void AddResponseHandler<TResponse>(IResponseHandler<TResponse> handler) where TResponse : class, IResponse
{
List<IResponseHandler<IResponse>> handlers;
_handlerMap.TryGetValue(typeof(TResponse), out handlers);
if (handlers == null)
{
handlers = new List<IResponseHandler<IResponse>>();
_handlerMap.Add(typeof(TResponse), handlers);
}
IResponseHandler<IResponse> myhandler = handler;
handlers.Add(myhandler);
}
public static void Handle<TResponse>(TResponse response) where TResponse : class, IResponse
{
List<IResponseHandler<IResponse>> handlers;
_handlerMap.TryGetValue(typeof(TResponse), out handlers);
if (handlers == null) return;
foreach (var handler in handlers)
{
(handler as ResponseHandler<TResponse>).Handle(response);
}
}
}
// and implementation...
class FirstResponse : IResponse { }
class AutomatedResponse : IResponse { }
class FirstHandler : ResponseHandler<FirstResponse>
{
public override void Handle(FirstResponse response) { }
}
class AutomatedHandler : ResponseHandler<AutomatedResponse>
{
public override void Handle(AutomatedResponse response) { }
}
// ...and a test...
var firsthandler = new FirstHandler();
var secondhandler = new AutomatedHandler();
TestHandler.AddResponseHandler(firsthandler);
TestHandler.AddResponseHandler(secondhandler);
var first = new FirstResponse();
var second = new AutomatedResponse();
TestHandler.Handle(first);
TestHandler.Handle(second);
有一些有趣的事情,快...
1)你需要out
-base interface
才能做到covariant
2)你需要keep it
协变——不要在其中添加任何东西Add
(见评论)。基本上(并且过于简化)你需要维护它read only
(标记这不是真的 - 只是更容易这样想)。这也适用于参与其中的所有类型/其他参数等。编译器将引导您出现错误
3)将所有功能从IResponseHandler
一个ResponseHandler
类中提取出来——所有的服务器——在那里你可以添加你的Add
等等——并针对特定情况进行覆盖
4)您需要cast
找到可以实际“处理”的“处理程序”-(handler as ResponseHandler<TResponse>).Handle(response);
笔记
...这完全是futile
如果您的“处理程序”只是“处理”(这Add
是您真正需要的唯一方法) - 即这完全取决于您的代码和结构以及事物的实现。如果您的基本界面“服务于目的”用于其他目的 - 那么它可能是值得的。否则——你几乎可以用它来做所有这些object
——然后从那里投object
下来,你不会对此感到更快乐或更快乐。