0

I have one base class that is used to declare generic data structures that have a fixed length in a datablock:

public abstract class FixedLengthDataItem
{

    // a static field here to store the fixed length?

    public sealed void LoadFromBytes(byte[] data)
    {
        // Check the fixed length here

        DoStuff(data, offset);
    }

    protected abstract void DoStuff(byte[] data);
}

There can be a lot of data structures that have a fixed length and my intent is to describe them in subclasses.

I'd like to know whether there is a possibility to transmit the information about the fixed length when declaring the inheritance in the child classes:

public class ChildClass : FixedLengthDataItem // Specific syntax here?
{
    public override void DoStuff(byte[] data)
    {
        // Some stuff
    }
}

I cannot find a syntax like : FixedLengthDataItem(2) or : FixedLengthDataItem<2> that would allow to set the value of a static field that would be declared in the mother class and could be used to "generically" check the length in the LoadFromBytes method (2 in my example).

If there is no way to do it, what could be a smart way to allow anyone to write subclasses making sure that the check that is performed in the LoadFromBytes method checks the right thing?

I thought about something like:

private readonly int _size;
protected FixedLengthDataItem(int size) { _size = size; }

in the base class. And:

public ChildClassFoo() : base(2) { } // or
public ChildClassBar() : base(3) { } // etc.

in the child class(es). But doing this:

  1. a constructor must be declared in each derived class,
  2. more important: a field size will exist in each object whereas the same size applies for all the instances of each derived class which is not very wise I guess.
Gab
  • 99
  • 2
  • 5

2 Answers2

0

For what you're describing, putting the size on the base class and then specifying it in the derived classes is better than using any sort of static field.

As you showed in your question:

public ChildClassFoo() : base(2) { } 
public ChildClassBar() : base(3) { } 

a constructor must be declared in each derived class

You've declared two derived classes in your example without constructors.

a field size will exist in each object whereas the same size applies for all the instances of each derived class which is not very wise I guess.

That would be exactly, precisely the point of putting that field in the base class. If every class that inherits from it needs a field size then what you're doing with the base class ensures that. It doesn't matter if two different classes happen to have the same field size.

Scott Hannen
  • 27,588
  • 3
  • 45
  • 62
0

Here is one way to do it. Not quite as clean as C++ templates but interesting regardless.

public abstract class DataSize
{
    protected DataSize(int size)
    {
        if (size < 0) 
            throw new ArgumentOutOfRangeException("Must be greater than zero.", nameof(size));
        Size = size;
    }

    public int Size { get; }
}  

public abstract class FixedLengthDataItem<TDataSize> 
    where TDataSize : DataSize, new()
{
    public static TDataSize Data { get; } = new TDataSize();

    // a static field here to store the fixed length?

    public void LoadFromBytes(byte[] data)
    {
        // Check the fixed length here
        if (data.Length != Data.Size)
        {
            throw new ArgumentException($"Data has size {data.Length} but a size of {Data.Size} was expected.", nameof(data));
        }

        DoStuff(data);
    }

    protected abstract void DoStuff(byte[] data);
}

public sealed class ItemData345 : DataSize { public ItemDataSize() : base(345) { } }

public sealed class CustomItem : FixedLengthDataItem<ItemData345>
{
    protected override void DoStuff(byte[] data)
    {
        throw new NotImplementedException();
    }
}

Lets say you have 3-4 classes of this size it actually pays of syntax wise. Space wise is a different story, you'll need so many instances for this to truly be worth it but it is an interesting experiment.

ChaosPandion
  • 77,506
  • 18
  • 119
  • 157