Simplify Generic Method I am writing a GenericDeserializer for Apache Kafka. My class implements IDeserializer&lt;T&gt; from Confluent.Kafka.Net package. I need to supply a Deserialize method which has this signature, T Deserialize(ReadOnlySpan&lt;byte&gt; data, bool isNull, SerializationContext context). But I also need to use Deserializers class of Confluent because it implements some low level details such as decoding a big endian message from network as primitive types, as byte array, as UTF8 string etc. How can I simplify this method. One example of simplification may be removing the use of casts which I introduced to make the compiler happy.
My logic in this method is like this, use every supported type in already implemented Deserializers class. For other types that are not deserialized with the help of this class, use Json Serialization. Here is my code:
public class GenericDeserializer&lt;T&gt; : IDeserializer&lt;T&gt;
{
    public T Deserialize(ReadOnlySpan&lt;byte&gt; 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&lt;T&gt;(data, new JsonSerializerOptions()
        {
            PropertyNameCaseInsensitive = true
        });
    }
}

Here is the source of Deserializers class from Confluent.Kafka
https://github.com/confluentinc/confluent-kafka-dotnet/blob/master/src/Confluent.Kafka/Deserializers.cs
You can define a mapping between Types and the Deserializers. You can do this for example like this:
public class GenericDeserializer&lt;T&gt; : IDeserializer&lt;T&gt;
{
    private readonly ImmutableDictionary&lt;Type, object&gt; _deserializers =
        new Dictionary&lt;Type, object&gt;
    {
        { 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();
}

You can't use the IDeserializer&lt;T&gt; in the Dictionary's Value type parameter that's why it is an object.
Then all you need to do is to make a lookup call and try to cast the value to IDeserializer&lt;T&gt;
if (_deserializers.ContainsKey(typeof(T)))
{
    var deserializer = _deserializers[typeof(T)] as IDeserializer&lt;T&gt;;
    ...
}

If the type was found then you can make branching based on the isNull value:
if (_deserializers.ContainsKey(typeof(T)))
{
    var deserializer = _deserializers[typeof(T)] as IDeserializer&lt;T&gt;;
    var retVal = deserializer.Deserialize(data, isNull, context);
    return !isNull ? retVal : default;
}

If it is not found then you can use the JsonSerializer as your fallback.
return JsonSerializer.Deserialize&lt;T&gt;(data, new JsonSerializerOptions()
{
    PropertyNameCaseInsensitive = true
});


The final code would look like this:
public class GenericDeserializer&lt;T&gt; : IDeserializer&lt;T&gt;
{
    private readonly ImmutableDictionary&lt;Type, object&gt; _deserializers =
        new Dictionary&lt;Type, object&gt;
    {
        { 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&lt;byte&gt; data, bool isNull, SerializationContext context)
    {
        if (_deserializers.ContainsKey(typeof(T)))
        {
            var deserializer = _deserializers[typeof(T)] as IDeserializer&lt;T&gt;;
            var retVal = deserializer.Deserialize(data, isNull, context);
            return !isNull ? retVal : default;
        }

        return JsonSerializer.Deserialize&lt;T&gt;(data, new JsonSerializerOptions()
        {
            PropertyNameCaseInsensitive = true
        });
    }
}