Question

I'm writing a system that has a set of protocol buffers (using protobuf-net), I want to define something like this in an abstract class they all inherit off:

public byte[] GetBytes()

however, the protocol buffer serealiser requires a type argument, is there some efficient way to get the type of the inheriting class?

Example:

public byte[] GetBytes()
    {
        using (MemoryStream stream = new MemoryStream())
        {
            Serializer.Serialize<T /* what goes here? */>(stream, this);
            return stream.ToArray();
        }
    }
Was it helpful?

Solution

Just write "T" right?

and then in your class declaration:

public class M<T>

?

-- Edit

And then when you inherit it:

public class Foo : M<Apple>

OTHER TIPS

You can do this via reflection, but protobuf-net did it for you.

Just change your call to:

Serializer.NonGeneric.Serialize(stream, this /* Takes an object here */);

This works by building the generic method at runtime via reflection. For details, check the code (second method here).

Define your base class as BaseClass<T> and then your derived classes replace T with the serializer type DerivedClass<SerializerType>.

You can also specify constraints on the type argument e.g.

BaseClass<T> where T : SerializerBase

Here is a description of the types of constraints you can apply.

You don't actually need anything special here... since protobuf-net respects inheritance. If you have:

[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 */ }

then it will work. To serialize the data, it always starts at the base (contract) type; so even if you did Serializer.Serialize<Foo>(stream, obj) the first thing it will do is detect that it has a base class that is a contract, and switch to MyBase. During deserialization it will identify the correct derived (concrete) type and use that, so you can use Deserialize with MyBase too, and it will construct a Foo or Bar depending on what the original data was.

Thus the following are largely identical:

Serializer.Serialize<BaseType>(dest, obj);
...
BaseType obj = Serializer.Deserialize<BaseType>(source);

and

Serializer.Serialize<DerivedType>(dest, obj);
...
DerivedType obj = Serializer.Deserialize<DerivedType>(source);

The main difference here is how the variables are typed.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top