Genel Yöntemi Basitleştirin
Apache Kafka için bir GenericDeserializer yazıyorum. Benim sınıfının uyguladığı IDeserializer<T>gelen Confluent.Kafka.Netpaketin. Bu imzaya sahip bir Deserialize yöntemi sağlamam gerekiyor T Deserialize(ReadOnlySpan<byte> data, bool isNull, SerializationContext context). Ama aynı zamanda DeserializersConfluent sınıfını da kullanmam gerekiyor çünkü ağdan büyük bir endian mesajının şifresini ilkel tipler olarak, bayt dizisi olarak, UTF8 dizesi olarak vb. Gibi bazı düşük seviyeli ayrıntıları uyguluyor. Bu yöntemi nasıl basitleştirebilirim. Basitleştirmenin bir örneği, derleyiciyi mutlu etmek için sunduğum yayınların kullanımını kaldırmak olabilir.
Bu yöntemdeki mantığım şöyle, zaten uygulanmış Deserializerssınıfta desteklenen her türü kullanın . Bu sınıfın yardımıyla serileştirilmemiş diğer türler için Json Serileştirmeyi kullanın. İşte kodum:
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
});
}
}
İşte Deserializerssınıfın kaynağıConfluent.Kafka https://github.com/confluentinc/confluent-kafka-dotnet/blob/master/src/Confluent.Kafka/Deserializers.cs
Yanıtlar
TypeS ve Deserializers. Arasında bir eşleme tanımlayabilirsiniz . Bunu örneğin şu şekilde yapabilirsiniz:
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>Sözlüğün Değer türü parametresinde kullanamazsınız, bu yüzden bir object.
O zaman yapmanız gereken tek şey bir arama araması yapmak ve değeri IDeserializer<T>
if (_deserializers.ContainsKey(typeof(T)))
{
var deserializer = _deserializers[typeof(T)] as IDeserializer<T>;
...
}
Tür bulunursa, isNulldeğere göre dallanma yapabilirsiniz :
if (_deserializers.ContainsKey(typeof(T)))
{
var deserializer = _deserializers[typeof(T)] as IDeserializer<T>;
var retVal = deserializer.Deserialize(data, isNull, context);
return !isNull ? retVal : default;
}
JsonSerializerBulunmazsa, yedeğiniz olarak kullanabilirsiniz .
return JsonSerializer.Deserialize<T>(data, new JsonSerializerOptions()
{
PropertyNameCaseInsensitive = true
});
Nihai kod şöyle görünecektir:
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
});
}
}
DeserializeYöntemdeki dallanmalardan kurtulabilir ve bunun yerine bu mantığı yalnızca bir kez yürütülen bir yere - inşaat yerine taşıyabilirsiniz. Örneğinizin bir örneği, GenericDeserializer<T>herhangi bir girdi için her zaman aynı dalı çalıştırır, çünkü örnek zaten belirli bir çıktı türüne bağlıdır. İnt ve double gibi türler için, uygulamalarını kullandığınız yerde yalnızca uygulamalarını döndürürseniz, uygulamanızı kullanın dinlenme.
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>();
}