他の人が言ったように-「あなたがやっている方法」でそれを行う方法はありません...
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);
興味のあることがいくつかありますが、すぐに...
out
1) 作るにはbase interface
-が必要ですcovariant
2)共変する必要がありますkeep it
-その中に何も追加しないでAdd
ください(コメントを参照)。基本的に(そして過度に単純化された)それを維持する必要がありますread only
(これは真実ではないことに注意してください-そのように考える方が簡単です)。また、それに参加するすべてのタイプ/その他のパラメーターなどにも当てはまります。コンパイラがエラーをガイドします
IResponseHandler
3)すべての機能をクラスに引き出しResponseHandler
ます-そのサーバーすべて-そこにあなたAdd
などを追加できます-特定のケースでオーバーライドします
cast
4)実際に「処理」できる「ハンドラー」に到達する必要があります-それ(handler as ResponseHandler<TResponse>).Handle(response);
ノート
...これは完全にfutile
、「ハンドラー」が「処理」のみの場合 (そしてそれAdd
が本当に必要な唯一のメソッド) です。つまり、これはコードと構造、および実装に完全に依存します。基本インターフェースがそれ以外の目的で「目的を果たす」場合、それは価値があるかもしれません。それ以外の場合は、ほぼすべてのことを行うことができobject
、キャストからキャストしてobject
も、それほど満足することはありません。