C# 通用处理程序,我有什么误解?

C# generic handlers, what am I misunderstanding?(C# 通用处理程序,我有什么误解?)
本文介绍了C# 通用处理程序,我有什么误解?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不确定为什么这不起作用.它不喜欢 TResponse 用于 out 和 handlerMap 添加,即使 TResponse 是 IResponse?我想我一定是对泛型有误解,或者更可能是对 C# 的误解.为什么这不起作用,有没有更好的方法来完成我在这里尝试做的事情?

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:

错误 1 ​​'System.Collections.Generic.Dictionary>>.TryGe‌ tValue(System.Type, out System.Collections.Generic.List>)' 的最佳重载方法匹配有一些无效参数 C:...NetworkManager.cs 39 13 组装‌ -CSharp-vs

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

错误 2 参数 2:无法从 'out System.Collections.Generic.List>' 转换为 'out System.Collections.Generic.List>' C:...NetworkManager.cs 39 61 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) 你需要 contravariance - Add 才能工作

a) You need contravariance - for the Add to work

b) 你需要 covariance 才能upcastIResponseHandlerIResponseHandler

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

(你也有另一个编译问题,将 out 返回到不同类型的 List 中,这两种方式都不能工作)...

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

对于一个解决方案 - 如果这个 contract 满足你的需要,你可以 trick 让它工作.当您失去一些支持时,这更像是一个实践示例" - 但取决于您需要什么......

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) 你需要 outbase interface - 使它成为 covariant

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

2) 您需要 保持它 协变 - 不要在其中添加任何内容,例如 Add(请参阅注释).基本上(并且过于简化)你需要维护它 read only (标记这不是真的 - 只是更容易这样想).这也适用于参与其中的所有类型/其他参数等.编译器将引导您出现错误

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) 将 IResponseHandler 中的所有功能提取到 ResponseHandler 类中 - 该服务器全部 - 在那里您可以添加您的 Add 等. - 并覆盖特定情况

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) 您需要 cast 才能获得真正可以处理"的处理程序" - (handler as ResponseHandler).Handle(response);

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

...如果您的处理程序"只是处理"(并且 Add 是您真正需要的唯一方法),这完全是 徒劳 - 即这个完全取决于你的代码和结构以及事物的实现.如果您的基本界面服务于目的"用于其他目的 - 那么它可能是值得的.否则 - 你几乎可以用 object 做所有这些 - 并从 object 投射,你不会对此感到更快乐或更快乐.

...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# 通用处理程序,我有什么误解?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本站部分内容来源互联网,如果有图片或者内容侵犯您的权益请联系我们删除!

相关文档推荐

DispatcherQueue null when trying to update Ui property in ViewModel(尝试更新ViewModel中的Ui属性时DispatcherQueue为空)
Drawing over all windows on multiple monitors(在多个监视器上绘制所有窗口)
Programmatically show the desktop(以编程方式显示桌面)
c# Generic Setlt;Tgt; implementation to access objects by type(按类型访问对象的C#泛型集实现)
InvalidOperationException When using Context Injection in ASP.Net Core(在ASP.NET核心中使用上下文注入时发生InvalidOperationException)
LINQ many-to-many relationship, how to write a correct WHERE clause?(LINQ多对多关系,如何写一个正确的WHERE子句?)