使用BinaryReader读/写可空类型?

Rid*_*Dev 4 c# nullable binary-serialization

我正在重载System.IO BinaryReader来序列化一些类以用于文件存储.我没有问题像字典这样的项目,但没有成功的可空类型.有可能吗?具体来说我正在尝试小数?和字符串?,但任何类型应该适合我调整我的解决方案.

出于特定的业务原因,我必须进行二进制序列化,因此请将响应限制为仅适用于此的解决方案.

例如...用于读取/写入字节数组我使用以下方法:

    public byte[] ReadByteArray()
    {
        int len = ReadInt32();
        if (len > 0) return ReadBytes(len);
        if (len < 0) return null;
        return new byte[0];
    }

    public override void Write(byte[] b)
    {
        int len = b.Length;
        Write(len);
        if (len > 0) base.Write(b);
    }
Run Code Online (Sandbox Code Playgroud)

Sco*_*ain 5

你需要添加某种标志,让读者知道它是否应该读取下一个字节.

public decimal? ReadNullableDecimal()
{
    bool hasValue = ReadBoolean();
    if (hasValue) return ReadDecimal();
    return null;
}

public void Write(decimal? val)
{
    bool hasValue = val.HasValue;
    Write(hasValue)
    if(hasValue)
        Write(val.Value);
}
Run Code Online (Sandbox Code Playgroud)

但是,我们可以聪明并创建一个适用于所有基于结构的类型的通用方法

public Nullable<T> ReadNullable<T>(Func<T> ReadDelegate) where T : struct
{
    bool hasValue = ReadBoolean();
    if (hasValue) return ReadDelegate();
    return null;
}

public void Write<T>(Nullable<T> val) where T : struct
{
    bool hasValue = val.HasValue;
    Write(hasValue)
    if(hasValue)
        Write(val.Value);
}
Run Code Online (Sandbox Code Playgroud)

如果我想使用我的ReadNullable函数来读取,Int32我会称之为

Int32? nullableInt = customBinaryReader.ReadNullable(customBinaryReader.ReadInt32);
Run Code Online (Sandbox Code Playgroud)

所以它会测试该值是否存在,然后如果它存在则会调用传入的函数.


编辑:睡觉后,该Write<T>方法可能无法像您期望的那样工作.因为T不是一个定义良好的类型,唯一可以支持它的方法是Write(object)二进制编写器不支持开箱即用.ReadNullable<T>仍然可以工作,如果你想使用仍然使用,Write<T>你将需要使val.Value 动态的结果.您需要进行基准测试,以确定是否存在任何性能问题.

public void Write<T>(Nullable<T> val) where T : struct
{
    bool hasValue = val.HasValue;
    Write(hasValue)
    if(hasValue)
        Write((dynamic)val.Value);
}
Run Code Online (Sandbox Code Playgroud)


use*_*736 -1

public decimal ReadDecimal()
{
    int len = ReadInt32();
    if (len > 0) return base.ReadDecimal();
    if (len < 0) return null;
    return new decimal;
}


public override void WriteDecimal(decimal d)
{
    if (d==null)
        WriteInt32(-1);
    else
    {
        WriteInt32(sizeof(d)); //16
        Write(d);
    }
}
Run Code Online (Sandbox Code Playgroud)