Using a IEnumerable where we have mostly only one item

Posted on

Problem

I have a project where I publish and subscribe some data packages. Mostly those data packages are just one package, but sometimes (1 in 100) there could be more packages at one time (a lot more, like 100.000 at the same time) I have a class PacketTransport which only has a IDataPacket property in it. I do this so I can serialize and deserialize it with JSON.net and the JsonSerializerSettings with TypeNameHandling = TypeNameHandling.Auto so the deserializer will know which kind of type it is.

I think about making IDataPacket to an IEnumerable<IDataPacket> so I will always enumerate eventhough there is just one data packet inside because when sometimes 100.000 Data Packages at a time are coming, my MQTT is overloaded with 100.000 PacketTransport packages and for the next minutes nothing else can pass. But as those 100.000 packets are mostly very small, I would like to pack it in one PacketTransport message.

So my question is: Is it bad to use an IEnumerable where most of the time only one item is inside it? Is the overhead that much or can I ignore it?

public class PacketTransport
{
    //Serialize with:
    //JsonConvert.SerializeObject(packetTransport, new() { TypeNameHandling = TypeNameHandling.Auto });
    public IEnumerable<IDataPacket> DataPackets { get; }

    public PacketTransport(IDataPacket dataPacket)
    {
        if (dataPacket is null) throw new ArgumentNullException(nameof(dataPacket));
        DataPackets = new[] { dataPacket }; //Is this the most efficient way?
    }

    public PacketTransport(IEnumerable<IDataPacket> dataPackets)
    {
        if (dataPackets is null) throw new ArgumentNullException(nameof(dataPackets));
        DataPackets = dataPackets.ToArray(); //Copy the original dataPackets
    }
}

public interface IDataPacket
{
    int Id { get; }
}

p.s.: I know, that my main bottleneck is probably the JSON serialization, I will go with protobuf in the future

Solution

Is it bad to use an IEnumerable where most of the time only one item is inside it?

This is perfectly fine. Checking for element counts and using either a collection or another variable would cause you more headaches and overhead than sticking to enumerables.


Is the overhead that much or can I ignore it?

You can ignore it… unless the profiler tells you otherwise.


DataPackets = new[] { dataPacket }; //Is this the most efficient way?

When you are looking for a materialized collection then I’m pretty sure it is and also the most elegant one. You could use linq like that but mhmm… I wouldn’t:

Enumerable.Repeat(dataPacket , 1)

The only area I would consider for maintainability of your code is to avoid repeating code i.e. “DRY”.

public class PacketTransport
{
    public IEnumerable<IDataPacket> DataPackets { get; }

    // constructor chaining
    public PacketTransport(IDataPacket dataPacket) 
        : this(new[] { dataPacket ?? throw new ArgumentNullException(nameof(dataPacket)) })
        { }

    public PacketTransport(IEnumerable<IDataPacket> dataPackets)
    {
        if (dataPackets is null) throw new ArgumentNullException(nameof(dataPackets));
        
        // now we have all the logic for construction in one place.
        DataPackets = dataPackets;
    }
}

Also note, that I don’t see the value of enumerating your collection IDataPacket> dataPackets in your constructor, as it doesn’t show any apparent value or “need”.

DataPackets = dataPackets.ToArray(); // <-- no obvious reason why you are doing this...

Leave a Reply

Your email address will not be published. Required fields are marked *