C#泛型处理程序,我是什么误会? [英] C# generic handlers, what am I misunderstanding?

查看:258
本文介绍了C#泛型处理程序,我是什么误会?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不知道为什么,这是行不通的。它不喜欢TResponse了出来,handlerMap增加,即使TResponse是IResponse?我想我一定是误解一些关于仿制药,或者更可能的是,关于C#。为什么不是这个工作,有没有更好的方式来完成我想在这里做?

 私有静态字典<类型,列表和LT; IResponseHandler< IResponse>>> _handlerMap;

公共静态无效AddResponseHandler< TResponse>(IResponseHandler< TResponse>处理),其中TResponse:IResponse
{
    名单< IResponseHandler< TResponse>>处理程序;
    _handlerMap.TryGetValue(typeof运算(TResponse),输出处理程序);

    如果(处理程序== NULL)
    {
        处理程序=新的名单,其中,IResponseHandler< TResponse>>();
        _handlerMap.Add(typeof运算(TResponse),处理程序);
    }

    handlers.Add(处理);
}

公共接口IResponseHandler< TResponse>其中,TResponse:IResponse
{
    无效手柄(TResponse响应);
}
 

我在编译过程中收到以下错误:

  

错误1的最佳重载方法匹配。System.Collections.Generic.Dictionary >> TryGe tValue(System.Type的,出System.Collections.Generic.List>)有一些无效的参数C:... \ NetworkManager.cs 39 13大会-CSharp-VS

     

错误2参数2:无法从走出System.Collections.Generic.List>'转换为'出来System.Collections.Generic.List> C:\ NetworkManager.cs 39 61大会-CSHARP-VS

 如果我改变TResponse到IResponse内的方法,上述一切
handlers.Add(处理)编译罚款。我不明白为什么我不能添加的处理程序
< TResponse:IResponse>到List< IResponseHandler< IReponse>>?
 

解决方案

正如其他人提到的 - 有没有办法做到这一点'你这样做'的方式......

a)你需要逆变 - 对添加工作

b)你需要要能够上溯造型 IResponseHandler< TResponse> IResponseHandler< IResponse>

(你也必须与返回的另一个编译问题退出成不同的充类型列表中无法正常工作两种方式)...

有关的解决方案 - 你能欺骗成工作之类的 - 如果此合同满足您的需要。它更多的是实践范例为你失去了一些支持的 - 而是取决于你所需要的......

 接口IResponse {}
接口IResponseHandler<出TResponse>
    其中,TResponse:类,IResponse
{
    //添加'只读'(简体)唯一属性 - 支持协方差 - 这意味着牛逼等,没有输入参数
    //无效手柄(TResponse响应);
}
抽象类ResponseHandler的< TResponse> :IResponseHandler< TResponse>
    其中,TResponse:类,IResponse
{
    公共抽象无效手柄(TResponse响应);
}
类TestHandler
{
    私有静态字典<类型,列表和LT; IResponseHandler< IResponse>>> _handlerMap =新字典<类型,列表和LT; IResponseHandler< IResponse>>>();
    公共静态无效AddResponseHandler< TResponse>(IResponseHandler< TResponse>处理),其中TResponse:类,IResponse
    {
        名单< IResponseHandler< IResponse>>处理程序;
        _handlerMap.TryGetValue(typeof运算(TResponse),输出处理程序);
        如果(处理程序== NULL)
        {
            处理程序=新的名单,其中,IResponseHandler< IResponse>>();
            _handlerMap.Add(typeof运算(TResponse),处理程序);
        }
        IResponseHandler< IResponse>将myHandler =处理程序;
        handlers.Add(将myHandler);
    }
    公共静态无效手柄< TResponse>(TResponse响应),其中TResponse:类,IResponse
    {
        名单< IResponseHandler< IResponse>>处理程序;
        _handlerMap.TryGetValue(typeof运算(TResponse),输出处理程序);
        如果(处理程序== NULL)回报;
        的foreach(在处理程序变种处理)
        {
            (处理程序ResponseHandler的< TResponse>)。手柄(响应);
        }
    }
}
//和实施...
类FirstResponse:IResponse {}
类AutomatedResponse:IResponse {}
类FirstHandler:ResponseHandler的< FirstResponse>
{
    公众覆盖无效手柄(FirstResponse响应){}
}
类AutomatedHandler:ResponseHandler的< AutomatedResponse>
{
    公众覆盖无效手柄(AutomatedResponse响应){}
}
// ...和测试...
VAR firsthandler =新FirstHandler();
VAR secondhandler =新AutomatedHandler();
TestHandler.AddResponseHandler(firsthandler);
TestHandler.AddResponseHandler(secondhandler);

VAR第一=新FirstResponse();
VAR秒=新AutomatedResponse();
TestHandler.Handle(第一);
TestHandler.Handle(第二);
 

有兴趣对夫妇的事情,快...

1)你必须退出基本接口上 - 让它

2)你需要保持协 - 通过不加了什么东西像添加(见注释)。基本上(和过于简化的),你需要保持它只读(标记,这是不正确的 - 只是更容易这样认为)。也有认为这适用于所有类型/其他PARAMS等参与其中。编译器将引导您瓦特/错误

3)拉出从 IResponseHandler 所有的功能整合到一个 ResponseHandler的类 - 该服务器的所有 - 有你可以添加添加等等 - 覆盖特定情况下

4)你需要铸造去的处理程序,可实际上是处理 - 即(处理程序ResponseHandler的< TResponse>。)手柄(响应);

注意

......,这完全是徒劳如果你的'处理'只是'处理'(和添加是你真正需要的唯一方法) - 即这完全取决于你的code和结构与事物的实施。如果你的基本接口服务的宗旨'的东西比其他的 - 那么它可能是值得的。否则 - 你可以做一切与对象 pretty的多 - 和施放距离对象,你不会任何更少或更多的快乐吧。

I'm not sure why this doesn't work. It doesn't like TResponse for the out and handlerMap add, even though TResponse is an IResponse? I figure I must be misunderstanding something about generics, or perhaps more likely, about C#. Why doesn't this work, and is there a better way to accomplish what I'm trying to do here?

private static Dictionary<Type, List<IResponseHandler<IResponse>>> _handlerMap;

public static void AddResponseHandler<TResponse>(IResponseHandler<TResponse> handler) where TResponse : IResponse
{
    List<IResponseHandler<TResponse>> handlers;
    _handlerMap.TryGetValue(typeof (TResponse), out handlers);

    if (handlers == null)
    {
        handlers = new List<IResponseHandler<TResponse>>();
        _handlerMap.Add(typeof (TResponse), handlers);
    }

    handlers.Add(handler);
}

public interface IResponseHandler<TResponse> where TResponse : IResponse
{
    void Handle(TResponse response);
}

I am getting these errors during compilation:

Error 1 The best overloaded method match for 'System.Collections.Generic.Dictionary>>.TryGe‌​tValue(System.Type, out System.Collections.Generic.List>)' has some invalid arguments C:...\NetworkManager.cs 39 13 Assembly‌​-CSharp-vs

Error 2 Argument 2: cannot convert from 'out System.Collections.Generic.List>' to 'out System.Collections.Generic.List>' C:...\NetworkManager.cs 39 61 Assembly-CSharp-vs

If I change TResponse to IResponse within the method, everything above
handlers.Add(handler) compiles fine. I don't understand why I can't add a handler of 
<TResponse : IResponse> to a List<IResponseHandler<IReponse>>?

解决方案

As others mentioned - there is no way to do it `the way you're doing it'...

a) You need contravariance - for the Add to work

b) You need covariance to be able to upcastfrom IResponseHandler<TResponse> to IResponseHandler<IResponse>

(also you have another compilation problem with returning out into differnt type of List which cannot work either way)...

For a solution - you could trick it into working sort of - if this contract satisfies what you need. It's more of a 'practice example' as you lose some of the support - but depends on what you need...

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);

There are couple things of interest, fast...

1) You need out on the base interface - to make it covariant

2) You need to keep it covariant - by not adding anything in it like Add (see the comment). Basically (and overly simplified) you need to maintain it read only (mark that this isn't true - just easier to think that way). Also that goes for all the types/other params etc. that participate in it. The compiler will guide you w/ errors

3) Pull out all the functionality from the IResponseHandler into a ResponseHandler class - that server all - there you can add your Add etc. - and override for specific cases

4) You'd need to cast to get to the 'handler' that can actually 'handle' - that (handler as ResponseHandler<TResponse>).Handle(response);

Note

...that this is entirely futile if your 'handler' is only 'handling' (and that Add is the only method you really need) - i.e. this fully depends on your code and structure and the implementation of things. If your base interface 'serves the purpose' for something other than that - then it might be worth it. Otherwise - you can do all that with object pretty much - and cast from object and you won't be any less or more happier about it.

这篇关于C#泛型处理程序,我是什么误会?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆