views:

57

answers:

2

I have an application that reads times from a file. These times can be in three different formats, based on flag bits elsewhere in the file, as shown below:

[StructLayout(LayoutKind.Sequential, Pack = 1]
public struct IntraPacketTime_RTC
{
    public UInt64 RTC;
}

[StructLayout(LayoutKind.Sequential, Pack = 1]
public struct IntraPacketTime_Ch4
{
    public UInt16 Unused;
    public UInt16 TimeHigh;
    public UInt16 TimeLow;
    public UInt16 MicroSeconds;
}

[StructLayout(LayoutKind.Sequential, Pack = 1]
public struct IntraPacketTime_IEEE1588
{
    public UInt32 NanoSeconds;
    public UInt32 Seconds;
}

As you can see, all three time formats take up eight bytes in the source data file, but these eight bytes are cast differently, depending on the specified time format.

However, the output time is always the same format, regardless of the way it is stored in the source data file (either YYY HH:MM:DD SS.ssssss, where ssssss is fractions of a second, or SSSSS.ssssss as seconds and fractional seconds past midnight).

How do I read these times from the data file and use them in a general way, without having case statements all over the place? Is there a software pattern that would simplify this, make it more generalized, and abstract away some of the complexity?

+1  A: 
[StructLayout(LayoutKind.Explicit)]
public struct IntraPacketTime {
    [FieldOffset(0)]
    private UInt64 RTC;

    [FieldOffset(0)]
    private UInt32 NanoSeconds;
    [FieldOffset(4)]
    private UInt32 Seconds;

    [FieldOffset(0)]
    private UInt16 Unused;
    [FieldOffset(2)]
    private UInt16 TimeHigh;
    [FieldOffset(4)]
    private UInt16 TimeLow;
    [FieldOffset(6)]
    private UInt16 MicroSeconds;        

    public DateTime GetTime(IntraPacketTimeFormat format) {
        switch (format) {
            ...
        }
    }
    public explicit operator IntraPacketTime(Int64 value) {
        return new IntraPacketTime { RTC = value; }
    }
}

public enum IntraPacketTimeFormat {
    None,
    RTC,
    Ch4,
    IEEE1588,
}

You should be able to use

IntraPacketTime t = (IntraPacketTime)binaryReader.ReadInt64();
var time = t.GetTime(IntraPacketTimeFormat.Ch4);
Mark H
Excellent, thanks.
Robert Harvey
A: 

I'd recommend a repository pattern.

class TimeReader
{
    public void ExtractTimeFormat(StreamReader data)
    {
        // read the flag and set state so that ExtractTime will return the
        // correct time implemenation
    }
    public ITime ExtractTime(StreamReader data)
    {
        // extract the appropriate time instance from the data based on
        // the current time format
    }
}

interface ITime
{
    void WriteTime(StreamWriter data);  
    void WriteTimeFlags(StreamWriter data);
    DateTime GetTime();
}

The only case statement is in ExtractTime, the rest of your code can act on abstractions.

David Gladfelter