Returning a byte array from a method public abstract class Element
{
    // Removed for verbosity ...

    protected abstract byte[] GetBytes();
}


I'm attempting to create an engine that can create a document in a very specific format. The document itself is composed of various elements, and each element has a very specific binary representation.

I originally thought that perhaps I should have an abstract method that returns a byte[] of the byte data will be written to a stream (file, memory, whatever). For example, one element would be formatted as so:

public sealed class ElementX : Element
{
    // Removed for verbosity ...

    public override byte[] GetBytes()
    {
        var nl      = Encoding.GetBytes("\r\n");
        var opening = Encoding.GetBytes("begin-elem-x");
        var closing = Encoding.GetBytes("end-elem-x");

        var data   = Encoding.GetBytes(Data);
        var result = Encoding.GetBytes(Result);

        return Util.BlockCopy(new[] { opening, nl, data, nl, closing, nl, result });
    }
}


The problem is that it just doesn't feel right to have a method that is meant for serialization. I thought about creating a custom serializer, but since each element is serialized in a very specific format (too much variation from element to element), I think that each element needs to own the code that allows it to determine the binary representation of itself; I don't know if a class exclusively for serialization of this format will work, as it would simply consist of a large if-else/switch branch and it would force me to expose private members as internal/protected/public so that this serializer could properly serialize the element.

I'm also not sure if there are any interfaces that specifically deal with this that are part of the Portable Class Libraries (ISerializable is not).

Additionally, I know there is a Code Analysis rule stating not to return a byte[] as a public property getter (CA1819: Properties should not return arrays). I don't think this necessarily applies to methods though.

I was thinking about using ImmutableArray from the Immutable Collections NuGet instead of byte[]. This seems to make sense because the value returned is immutable at the time; the value returned will only be different if a property value on the class is changed.
I could be wrong, but I haven't seen other designs of serialization than :


Serializer with reflection (customizable through attributes/converter/mapper).

This design is more complicated, in a sense that you have to plan ahead every the possible details of serialization. It is also harder to wire everything up, while leaving room for customization.


  it would simply consist of a large if-else/switch branch


This really shouldn't happen unless you plan to do this : switch(element.GetType().Name). You should use reflection to pull every member or property(pick one), and use Attribute to filter amd format them. The only switch you might need to have is opposibly for the premitive types : string, int, enum, etc.


  it would force me to expose private members as internal/protected/public


You don't have to, as you can obtain information on any member of a class, be protected or private.
Serializable by exposing a serialize method

This design is more straight-forward where each element serializes its own stuffs and delegates the rest to the respective element.




I'm going to assume the document is composed of hierarchical elements. If that is case, copying and merging the bytes array could get very costly, more as we get closer to the root element. Since you mentionned that you're working with a "very specific binary representation" and writing to a "stream", it would be best to write directly on the stream, rather than copying and merging the bytes, and holding them around.

public abstract class Element
{
    // Removed for verbosity ...

    protected abstract void Serialize(BinaryWriter writer);
}

public class ElementX : Element
{
    public string Result { get; set; }
    public Element Data { get; set; }

    protected override void Serialize(BinaryWriter writer)
    {
        const string NewLine = "\r\n";
        const string Opening = "begin-elem-x";
        const string Closing = "end-elem-x";

        writer.Write(Opening);
        writer.Write(NewLine);
        writer.Write(Data);
        writer.Write(NewLine);
        writer.Write(Closing);
        writer.Write(Result);
    }
}

internal static class SerializationExtensions
{
    public static void Write(this BinaryWriter writer, Element element)
    {
        element.Serialize(writer);
    }
}