代码之家  ›  专栏  ›  技术社区  ›  Karlovsky120

在泛型类中使用BinaryWriter

  •  1
  • Karlovsky120  · 技术社区  · 7 年前
    [Serializable]
    public class Vector3D<T> {
        public T x;
        public T y;
        public T z;
    }
    

    我需要从一个文件中读取它,然后再存储它。

    它通常看起来像这样:

    someCoord = new Vector3D<int> {
                    x = reader.ReadInt32(),
                    y = reader.ReadInt32(),
                    z = reader.ReadInt32()
                };
    writer.Write(someCoord.x);
    writer.Write(someCoord.y);
    writer.Write(someCoord.z);
    

    我想把这些话变成这样:

    someCoord = new Vector3D<int>(reader);
    someCoord.Write(writer);
    

    我会在Vector3D类中读写方法。虽然写作不是问题,因为我可以做以下事情:

    writer.Write((T)x)
    

    尝试以相同的方式读取会成为一个问题,因为我必须调用具有不同名称的方法,这取决于我要读取的类型。

    尽管如此,还有什么聪明的方法可以实现这一点吗?

    我会有一个字典,在那里我会保留类型-函数(委托)对,这样当我想读一些东西时,我会调用一些东西,比如:

    T value = reader.dictionary[T]();
    

    其中reader是BinaryReader的实例。如果T是int,dictionary[T]将替换为readInt32,如果T是float,dictionary[T]将替换为readSingle,以此类推。

    你知道如何做到这一点吗?

    1 回复  |  直到 7 年前
        1
  •  0
  •   Transcendent    7 年前

    您可以创建一个泛型方法,该方法依赖于 <T>

        public static Object GetValue<T>(BinaryReader br) {
            switch (Type.GetTypeCode(typeof(T)))
            {
                case TypeCode.Boolean: { return br.ReadBoolean(); }
                case TypeCode.Byte: { return br.ReadByte(); }
                case TypeCode.Char: { return br.ReadChar(); }
                case TypeCode.Decimal: { return br.ReadDecimal(); }
                case TypeCode.Double: { return br.ReadDouble(); }
                case TypeCode.Int16: { return br.ReadInt16(); }
                case TypeCode.Int32: { return br.ReadInt32(); }
                case TypeCode.Int64: { return br.ReadUInt64(); }
                // Keep on going for other types
                default: { return br.Read(); }
            }
        }
    

    这里有一个完整的例子

    public class Vector3D<T>
    {
        public T X { get; set; }
        public T Y { get; set; }
        public T Z { get; set; }
        private readonly String filePath;
        public Vector3D(String filePath) {
            this.filePath = filePath;
            if (File.Exists(filePath))
            {
                using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read)) {
                    using(BinaryReader br = new BinaryReader(fs))
                    {
                        X = (T) GetValue<T>(br);
                        Y = (T) GetValue<T>(br);
                        Z = (T) GetValue<T>(br);
                    }
                }
            }
        }
    
        public static Object GetValue<T>(BinaryReader br) {
            switch (Type.GetTypeCode(typeof(T)))
            {
                case TypeCode.Boolean: { return br.ReadBoolean(); }
                case TypeCode.Byte: { return br.ReadByte(); }
                case TypeCode.Char: { return br.ReadChar(); }
                case TypeCode.Decimal: { return br.ReadDecimal(); }
                case TypeCode.Double: { return br.ReadDouble(); }
                case TypeCode.Int16: { return br.ReadInt16(); }
                case TypeCode.Int32: { return br.ReadInt32(); }
                case TypeCode.Int64: { return br.ReadUInt64(); }
                default: { return br.Read(); }
            }
        }
    }
    

    您还可以为此创建扩展方法:

    public static class BinaryReaderExtensions
    {
        public static Object GetValue(this BinaryReader br, Type type)
        {
            switch (Type.GetTypeCode(type))
            {
                case TypeCode.Boolean: { return br.ReadBoolean(); }
                case TypeCode.Byte: { return br.ReadByte(); }
                case TypeCode.Char: { return br.ReadChar(); }
                case TypeCode.Decimal: { return br.ReadDecimal(); }
                case TypeCode.Double: { return br.ReadDouble(); }
                case TypeCode.Int16: { return br.ReadInt16(); }
                case TypeCode.Int32: { return br.ReadInt32(); }
                case TypeCode.Int64: { return br.ReadUInt64(); }
                default: { return br.Read(); }
            }
        }
    }