简体   繁体   English

将通用类型转换为其基本类型,反之亦然

[英]Converting generic type to its base and vice-versa

Can someone help me with the conversion I am facing in enclosed code ... I commented the lines of code, where I am having problem. 有人可以用封闭代码帮助我进行转换吗?我在存在问题的代码行中进行了注释。 Is this even the right way to achieve this ... what I am trying to do, is forward responses of specified type to provided callback. 这是否是实现此目标的正确方法……我想做的就是将指定类型的响应转发给提供的回调。

EDIT 1 编辑1

I forgot to mention that Response and AFResponse are abstract classes, which goes: >Response -> AFResponse -> concrete implementations of AF layer messages 我忘了提到Response和AFResponse是抽象类,它是:> Response-> AFResponse-> AF层消息的具体实现

public class MessageBinder
{
    private class Subscriber<T> : IEquatable<Subscriber<T>> where T : Response
    {
        ...
    }

    private readonly Dictionary<Type, List<Subscriber<Response>>> bindings;

    public MessageBinder()
    {
        this.bindings = new Dictionary<Type, List<Subscriber<Response>>>();
    }

    public void Bind<TResponse>(short shortAddress, Action<ZigbeeAsyncResponse<TResponse>> callback)
        where TResponse : Response
    {
        List<Subscriber<TResponse>> subscribers = this.GetSubscribers<TResponse>();
        if (subscribers != null)
        {
            subscribers.Add(new Subscriber<TResponse>(shortAddress, callback));
        }
        else
        {
            var subscriber = new Subscriber<TResponse>(shortAddress, callback);

            // ERROR: cannot convert from 'List<Subscriber<TResponse>>' to 'List<Subscriber<Response>>' ... tried LINQ Cast operator - does not work either
            this.bindings.Add(typeof(TResponse), new List<Subscriber<TResponse>> { subscriber });
        }
    }

    public void Forward<TResponse>(TResponse response)
        where TResponse : Response
    {
        var subscribers = this.GetSubscribers<TResponse>();
        if (subscribers != null)
        {
            Subscriber<TResponse> subscriber;
            Type responseType = typeof (TResponse);

            if (responseType.IsSubclassOf(typeof (AFResponse)))
            {
                // ERROR: Cannot convert type 'TResponse' to 'AFResponse' ... tried cast to object first, works, but is this the right way?
                var afResponse = (AFResponse)response;
                subscriber = subscribers.SingleOrDefault(s => s.ShortAddress == afResponse.ShortAddress);
            }
            else
            {
                subscriber = subscribers.First();
            }

            if (subscriber != null)
            {
                subscriber.Forward(response);
            }
        }
    }

    private List<Subscriber<TResponse>> GetSubscribers<TResponse>() where TResponse : Response
    {
        List<Subscriber<Response>> subscribers;
        this.bindings.TryGetValue(typeof(TResponse), out subscribers);

        // ERROR: How can I cast List<Subscriber<Response>> to List<Subscriber<TResponse>>?
        return subscribers;
    }
}

Thank you for any help :) 感谢您的任何帮助 :)

EDIT 2 编辑2

I changed the code according to @Bojan answer, and it is working. 我根据@Bojan答案更改了代码,并且可以正常工作。 But I am curious, why the Dictionary can't hold the base class of all Response messages? 但是我很好奇,为什么词典不能容纳所有Response消息的基类? Is there even a way to accomplish that, or did I just tried to push my head through a wall? 甚至有办法做到这一点,还是我只是试着将自己的头推过一堵墙?

EDIT 3 编辑3

Now I am facing another problem ... when message arrive, it is composed of byte array, >which goes to message factory which resolves and builds it: 现在,我面临另一个问题...当消息到达时,它由字节数组组成,>将转到消息工厂来解析并构建它:

public static T Build<T>(Packet packet) where T : Response
{
    Type resolvedType;
    if (!dependencyMap.TryGetValue(packet.MessageId, out resolvedType))
    {
        var str = String.Format("Could not resolve message. Message info: CMD0: {0}, CMD1: {1}, MessageID: {2}",
                                packet.Cmd0, packet.Cmd1, packet.MessageId);
        Debug.WriteLine(str);

        throw new MessageNotFoundException(str);
    }

    ConstructorInfo firstConstructor = resolvedType.GetConstructors().First();

    return (T) firstConstructor.Invoke(new object[] {packet});
}

Then an OnAsyncResponseReceived(Response response) event handler is invoked, which then forwards message to the subscriber of this message, if any. 然后, 调用OnAsyncResponseReceived(Response response)事件处理程序,然后将其转发给该消息的订户(如果有)。 The problem is now that if I subscribe to (sub layer of response are: AFResponse, SystemResponse, etc...) SystemResetResponse which is subclass of SystemResponse which is subclass of Response, that I must cast that response from Response(base) type all the way to the concrete type, which is SystemResetResponse in order the Forwarder in MessageBinder can find subscribers of this message type, and forwards it. 现在的问题是,如果我订阅(响应的子层是:AFResponse,SystemResponse等),则SystemResetResponse是SystemResponse的子类,而SystemResponse是Response的子类,我必须将该响应从Response(base)类型全部转换为通往具体类型的路径,即SystemResetResponse,以便MessageBinder中的转发器可以找到此消息类型的订户并进行转发。

There are many types and casting by hand would be an overkill ... is there a way around this, or even a better way to design this type of system? 有很多类型,手工铸造将是一个过大的选择...有没有解决的办法,或者甚至有更好的方法来设计这种类型的系统?

EDIT 4 编辑4

I changed a code like this ... is this the right way to do this, is there any other, better way and over all, am I trying to solve the problem the right way or is there better way to handle this? 我更改了这样的代码...这是执行此操作的正确方法吗,还有其他更好的方法吗?总体而言,我是在尝试以正确的方式解决问题还是有更好的方法来解决此问题?

private void OnAsyncResponseReceived(Response response)
{
    dynamic resolvedResponse = Convert.ChangeType(response, response.GetType());
    messageBinder.Forward(resolvedResponse);
}

You need to cast each item in subscribers list to Subscriber<TResponse> . 您需要将subscribers列表中的每个项目都Subscriber<TResponse>Subscriber<TResponse> Something like this always works for me - 这样的事情总是对我有用-

private List<T> get<T>()
    {
        List<IEntity> list = new List<IEntity>();
        List<T> genericList = new List<T>();
        foreach (var item in list)
        {
            genericList.Add((T)item);
        }
        return genericList;
    }

Hope it helps!! 希望能帮助到你!!

As well as the answer already provided, the following lines of code... 以及已经提供的答案,以下几行代码...

    Type responseType = typeof (TResponse);
    if (responseType.IsSubclassOf(typeof (AFResponse)))

Could be replaced with either: 可以替换为:

    if (response is AFResponse)

or (better) 或更好)

    AFResponse af = response as AFResponse;
    if (af != null)

EDIT Updated the code because I didn't realise beforehand that TResponse was a generic. 编辑更新了代码,因为我之前没有意识到TResponse是通用的。 Are you also aware that IsSubclassOf returns false if its a matching type? 您是否还知道IsSubclassOf如果匹配类型则返回false?

Part of your problem is that you are trying to declare your dictionary as having generic subscribers ( List<Subscriber<Response>> ), while expecting each entry to be of an unrelated type ( List<Subscriber<TResponse>> ). 问题的一部分是,您试图将字典声明为具有通用订阅者( List<Subscriber<Response>> ),同时期望每个条目都是不相关的类型( List<Subscriber<TResponse>> )。 A solution would be to hide the actual type behind object or IList : 一种解决方案是将实际类型隐藏在objectIList后面:

private readonly Dictionary<Type, object> bindings;

private List<Subscriber<TResponse>> GetSubscribers<TResponse>() 
    where TResponse : Response
{
    object subscribers;
    bindings.TryGetValue(typeof(TResponse), out subscribers);

    return (List<Subscriber<TResponse>>)subscribers;
}

Your Forward method can check for AFResponse and subclasses in a bit easier way, but the cast will have to go through object : 您的Forward方法可以以更简单的方式检查AFResponse和子类,但是AFResponse转换必须通过object

public void Forward<TResponse>(TResponse response)
    where TResponse : Response
{
    var subscribers = GetSubscribers<TResponse>();
    if (subscribers != null)
    {
        Subscriber<TResponse> subscriber;

        var afResponse = response as AFResponse;
        if (afResponse != null)
        {
            subscriber = subscribers.SingleOrDefault(s => s.ShortAddress == afResponse.ShortAddress);
        }
        else
        {
            subscriber = subscribers.First();
        }

        if (subscriber != null)
        {
            subscriber.Forward(response);
        }
    }
}

UPDATE 更新

You did not declare your dictionary to hold "base class of all messages". 您没有声明字典包含“所有消息的基类”。 Even though Response is the base class of all responses, Subscriber<Response> and Subscriber<T> are unrelated types. 尽管Response是所有响应的基类,但是Subscriber<Response>Subscriber<T>是不相关的类型。 It is somewhat analogous to how List<int> and List<string> are not related, even though both string and int inherit from object . 即使stringint都从object继承,它还是有点类似于List<int>List<string>不相关的方式。

What you are looking for is called covariance and is only supported by some interfaces. 您要查找的内容称为协方差 ,仅某些接口支持。

For example, if you had: 例如,如果您有:

interface ISubscriber<out T> where T:Response
{}

class Subscriber<T> : ISubscriber<T> where T:Response
{}

You could do: 您可以这样做:

ISubscriber<Response> s = new Subscriber<AFResponse>();

However, List<ISubscriber<Response>> and List<ISubscriber<AFResponse>> would still be unrelated types. 但是, List<ISubscriber<Response>>List<ISubscriber<AFResponse>>仍将是不相关的类型。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 将字典列表转换为字符串,反之亦然 - converting list of dictionaries to string and vice-versa 如何从无符号类型的通用参数中得出带符号的类型,反之亦然? - How to derive signed type from unsigned type generic parameter, and vice-versa? 在C#中将字符串数组转换为简单字符串,反之亦然 - converting an array of strings into a simple string and vice-versa in c# 在z#中将zenkaku字符转换为hankaku,反之亦然 - Converting zenkaku characters to hankaku and vice-versa in C# 在C#中将十进制数组转换为字节数组,反之亦然 - Converting decimal array to byte array and vice-versa in C# 在C#中将数字数组通用转换为字节,反之亦然 - Generic conversion of number arrays into bytes and vice-versa in C# XML到数据库,反之亦然 - XML to database and vice-versa 是否可以将整数(short,int,long)转换为以64为基数的字符串(反之亦然)? - Is it possible to convert an integer ( short, int, long ) into a base 64 string ( and vice-versa )? 从二进制形式转换浮动NaN值反之亦然导致不匹配 - Converting float NaN values from binary form and vice-versa results a mismatch 将BigInteger变量写入BitArray,反之亦然 - Write a BigInteger variable into a BitArray and vice-versa
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM