首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >简化泛型法

简化泛型法
EN

Code Review用户
提问于 2020-10-15 20:07:55
回答 2查看 314关注 0票数 6

我正在为Apache编写一个GenericDeserializer。我的类从IDeserializer<T>包实现了Confluent.Kafka.Net。我需要提供一个具有此签名的反序列化方法,T Deserialize(ReadOnlySpan<byte> data, bool isNull, SerializationContext context)。但我也需要使用汇流的Deserializers类,因为它实现了一些低层次的细节,例如将网络中的大endian消息解码为原语类型、字节数组、UTF8字符串等。简化的一个例子可能是删除我为使编译器高兴而引入的强制转换的使用。

我在这个方法中的逻辑是这样的,在已经实现的Deserializers类中使用每个受支持的类型。对于没有在该类的帮助下反序列化的其他类型,请使用Json序列化。这是我的代码:

代码语言:javascript
复制
public class GenericDeserializer<T> : IDeserializer<T>
{
    public T Deserialize(ReadOnlySpan<byte> data, bool isNull, SerializationContext context)
    {
        var type = typeof(T);

        if (type == typeof(double))
        {
            var retVal = Deserializers.Double.Deserialize(data, isNull, context);

            return (T) (object) retVal;
        }
        if (type == typeof(float))
        {
            var retVal = Deserializers.Single.Deserialize(data, isNull, context);

            return (T) (object) retVal; 
        }
        if (type == typeof(int))
        {
            var retVal = Deserializers.Int32.Deserialize(data, isNull, context);

            return (T) (object) retVal; 
        }
        if (type == typeof(long))
        {
            var retVal = Deserializers.Int64.Deserialize(data, isNull, context);

            return (T) (object) retVal; 
        }
        if (type == typeof(Null))
        {
            var retVal = Deserializers.Null.Deserialize(data, isNull, context);

            return (T) (object) retVal; 
        }
        if (type == typeof(string))
        {
            var retVal = Deserializers.Utf8.Deserialize(data, isNull, context);

            return (T) (object) retVal; 
        }
        if (type == typeof(byte[]))
        {
            var retVal = Deserializers.ByteArray.Deserialize(data, isNull, context);

            return (T) (object) retVal; 
        }
        if (isNull)
        {
            return default;
        }
        
        return JsonSerializer.Deserialize<T>(data, new JsonSerializerOptions()
        {
            PropertyNameCaseInsensitive = true
        });
    }
}

以下是Deserializers类的Confluent.Kafka https://github.com/confluentinc/confluent-kafka-dotnet/blob/master/src/Confluent.Kafka/Deserializers.cs的来源

EN

回答 2

Code Review用户

回答已采纳

发布于 2020-10-16 14:46:37

您可以定义Types和Deserializers之间的映射。例如,您可以这样做:

代码语言:javascript
复制
public class GenericDeserializer<T> : IDeserializer<T>
{
    private readonly ImmutableDictionary<Type, object> _deserializers =
        new Dictionary<Type, object>
    {
        { typeof(double), Deserializers.Double },
        { typeof(float), Deserializers.Single },
        { typeof(int), Deserializers.Int32 },
        { typeof(long), Deserializers.Int64 },
        { typeof(Null), Deserializers.Null },
        { typeof(string), Deserializers.Utf8 },
        { typeof(byte[]), Deserializers.ByteArray },
    }.ToImmutableDictionary();
}

您不能在字典的值类型参数中使用IDeserializer<T>,这就是为什么它是一个object

然后,您所需要做的就是进行查找调用,并尝试将值转换为IDeserializer<T>

代码语言:javascript
复制
if (_deserializers.ContainsKey(typeof(T)))
{
    var deserializer = _deserializers[typeof(T)] as IDeserializer<T>;
    ...
}

如果找到了该类型,则可以根据isNull值进行分支:

代码语言:javascript
复制
if (_deserializers.ContainsKey(typeof(T)))
{
    var deserializer = _deserializers[typeof(T)] as IDeserializer<T>;
    var retVal = deserializer.Deserialize(data, isNull, context);
    return !isNull ? retVal : default;
}

如果找不到它,那么可以使用JsonSerializer作为后盾。

代码语言:javascript
复制
return JsonSerializer.Deserialize<T>(data, new JsonSerializerOptions()
{
    PropertyNameCaseInsensitive = true
});

最后的代码如下所示:

代码语言:javascript
复制
public class GenericDeserializer<T> : IDeserializer<T>
{
    private readonly ImmutableDictionary<Type, object> _deserializers =
        new Dictionary<Type, object>
    {
        { typeof(double), Deserializers.Double },
        { typeof(float), Deserializers.Single },
        { typeof(int), Deserializers.Int32 },
        { typeof(long), Deserializers.Int64 },
        { typeof(Null), Deserializers.Null },
        { typeof(string), Deserializers.Utf8 },
        { typeof(byte[]), Deserializers.ByteArray },
    }.ToImmutableDictionary();

    public T Deserialize(ReadOnlySpan<byte> data, bool isNull, SerializationContext context)
    {
        if (_deserializers.ContainsKey(typeof(T)))
        {
            var deserializer = _deserializers[typeof(T)] as IDeserializer<T>;
            var retVal = deserializer.Deserialize(data, isNull, context);
            return !isNull ? retVal : default;
        }

        return JsonSerializer.Deserialize<T>(data, new JsonSerializerOptions()
        {
            PropertyNameCaseInsensitive = true
        });
    }
}
票数 3
EN

Code Review用户

发布于 2020-10-16 05:18:22

您可以摆脱Deserialize方法中的分支,而是将该逻辑移到只执行一次的位置--构造位置。对于任何输入,GenericDeserializer<T>的一个实例总是执行相同的分支,因为该实例已经绑定到特定的输出类型T中,例如int,并且在使用它们的实现时加倍--只返回它们的实现,其余的使用您的实现。

代码语言:javascript
复制
class JsonDeserializer<T> : IDeserializer<T>
{
    public T Deserialize(ReadOnlySpan<byte> data, bool isNull, SerializationContext context)
    {
        if (isNull)
        {
            return default;
        }
        
        return JsonSerializer.Deserialize<T>(data, new JsonSerializerOptions()
        {
            PropertyNameCaseInsensitive = true
        });
    }
}


IDeserializer<T> CreateDeserializer<T>()
{
    var type = typeof(T);

    if (type == typeof(double))
    {
        return (IDeserializer<T>) Deserializers.Double;
    }

    if (type === typeof(long))
    {
        return (IDeserializer<T>) Deserializers.Int64;
    }

    // ...

    return new JsonDeserializer<T>();
}
票数 0
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/250719

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档