I'm trying to build a functional package parser. I have a base class Datagram, now I was naively imagining I'd have it defined like this:
(Note on edit, this class is not abstract!)
public class Datagram
{
public abstract static Datagram CreateFromDatagram(Datagram datagram);
}
And then for specfic datagrams, say Ethernet and Tcp as an exampe:
public class EthernetDatagram : Datagram, IPayloadDatagram
{
public override static Datagram CreateFromDatagram(Datagram datagram)
{
return new EthernetDatagram();
}
public Datagram Payload { get; }
}
public class TcpDatagram : Datagram, IPayloadDatagram
{
public overrides static Datagram CreateFromDatagram(Datagram datagram)
{
return new TcpDatagram();
}
public Datagram Payload { get; }
}
The reason for this (impossible) abstract static method is I want to have an extension method which allows me to "chain" all these packets together:
public static class DatagramExtensions
{
public static T As<T>(this IPayloadDatagram datagram) where T : Datagram
{
return (T)T.CreateFromDatagram(datagram.Payload);
}
}
So, all I'd need to do to have a completely new datagram type ANewDatagram is have it define it's factory method CreateFromDatagram, and I'll be able to then merrily use my functional extension:
SomeDatagram.As<EthernetDatagram>().As<TcpDatagram>().As<ANewDatagram>()...
and it'll all be extensible.
Given this isn't going to work as I can't inherit abstract classes, what would be a good alternative to instantiating a generic class like this?
I could use reflection, but then that's hiding it from the user. When I try create ANewDatagram I have to remember that I'm reflecting a CreateFromDatagram method later on.
I am currently using reflection to get the constructor - but there's no way for me to enforce there's a specific constructor that takes the payload. If someone creates a new Datagram there's no guarantee they add the right constructor, I'd have to inform them this in comments, which will very likely be missed, and the point of failure is at run-time at the latest possible point.
Is there a better alternative, architecturally, or with some form of interface/inheritence that could get around this issue?
(If anyone wants to see the full source code I'm working with, I'm trying to add these extensions to the packet interpretation library as part of https://github.com/PcapDotNet/Pcap.Net, with as little modification as possible)