Tipo generico C# in una classe base
-
18-09-2019 - |
Domanda
Sto scrivendo un sistema che ha una serie di buffer di protocollo (usando protobuf-net), voglio definire qualcosa di simile in una classe astratta da cui tutti ereditano:
public byte[] GetBytes()
tuttavia, il serializzatore del buffer di protocollo richiede un argomento di tipo, esiste un modo efficiente per ottenere il tipo della classe ereditaria?
Esempio:
public byte[] GetBytes()
{
using (MemoryStream stream = new MemoryStream())
{
Serializer.Serialize<T /* what goes here? */>(stream, this);
return stream.ToArray();
}
}
Soluzione
Basta scrivere "T", giusto?
e poi nella dichiarazione di classe:
public class M<T>
- Modifica
E poi, quando si eredita esso:
public class Foo : M<Apple>
Altri suggerimenti
È possibile farlo attraverso la riflessione, ma protobuf-net ha fatto per voi.
Basta cambiare la chiamata a:
Serializer.NonGeneric.Serialize(stream, this /* Takes an object here */);
Questo funziona con la costruzione del metodo generico a runtime attraverso la riflessione. Per i dettagli, controllare il codice (secondo metodo qui ).
Definire la classe di base come BaseClass<T>
e quindi i vostri classi derivate sostituire T con il tipo serializzatore DerivedClass<SerializerType>
.
È inoltre possibile specificare i vincoli sul tipo di argomento per es.
BaseClass<T> where T : SerializerBase
Qui è una descrizione di è possibile applicare i tipi di vincoli.
In realtà non hai bisogno di niente di speciale qui...poiché protobuf-net rispetta l'ereditarietà.Se hai:
[ProtoInclude(typeof(Foo), 20)]
[ProtoInclude(typeof(Bar), 21)]
public abstract class MyBase {
/* other members */
public byte[] GetBytes()
{
using(MemoryStream ms = new MemoryStream())
{
Serializer.Serialize<MyBase>(ms, this); // MyBase can be implicit
return ms.ToArray();
}
}
}
[ProtoContract]
class Foo : MyBase { /* snip */ }
[ProtoContract]
class Bar : MyBase { /* snip */ }
allora funzionerà.Per serializzare i dati, it inizia sempre dal tipo base (contratto).;quindi anche se lo facessi Serializer.Serialize<Foo>(stream, obj)
la prima cosa che farà è rilevare che ha una classe base che è un contratto e passare a essa MyBase
.Durante la deserializzazione identificherà il tipo derivato (concreto) corretto e lo utilizzerà, in modo da poterlo utilizzare Deserialize
con MyBase
anche, e costruirà a Foo
O Bar
a seconda di quali fossero i dati originali.
Pertanto i seguenti sono in gran parte identici:
Serializer.Serialize<BaseType>(dest, obj);
...
BaseType obj = Serializer.Deserialize<BaseType>(source);
E
Serializer.Serialize<DerivedType>(dest, obj);
...
DerivedType obj = Serializer.Deserialize<DerivedType>(source);
La differenza principale qui è il modo in cui vengono digitate le variabili.