首页 > 解决方案 > 有什么方法可以防止/检测自动/隐式类型转换?

问题描述

考虑这些方法,每个方法都从输入缓冲区中提取字节:

byte ReadByte(List<byte> data); //removes and returns 1 byte
UInt16 ReadUInt16(List<byte> data); //removes and returns 2 bytes as a short
UInt32 ReadUInt32(List<byte> data); //removes and returns 4 bytes as an int

现在我有一个结构/类,如:

class Thing
{
 public byte a{get;set;}
 public UInt16 b{get;set;}
 public UInt32 c{get;set;}
 public byte d{get;set;}

 public void Read(List<byte> data)
 {
  a = ReadByte(data);
  b = ReadUInt16(data);
  c = ReadUInt16(data); //BUG this is a 32bit data
  d = ReadByte(data);
 }
}

因为 ashort会自动提升为 a int,所以这段代码编译并运行良好,但引入了一种很难找到的错误——它读取的字节数比它应该读取的少 2 个字节,c并且所有后续读取的值都是错误的。

是否有任何技术可用于确保当c是 type时UInt32,它​​不会接受 aUInt16或其他合法类型?

理想情况下Thing不会改变,但如果您的解决方案需要它,那没关系。

标签: c#.net

解决方案


答案是:对于您提供的方法不适用。

比如C#和.NET的CTS设计,就无法避免这样的编码错误。

但是就是说,您可以做的一件事是使用这样的通用方法:

static T Read<T>(this T instance, List<byte> data)
{
  switch ( instance )
  {
    case byte value:
      Console.WriteLine("Read byte");
      return default;
    case UInt16 value:
      Console.WriteLine("Read UInt16");
      return default;
    case UInt32 value:
      Console.WriteLine("Read Uint32");
      return default;
    default:
      string message = $"Type not supported for Read<T> (only byte or UInt16/32): "
                     + $"{typeof(T).Name}";
      throw new ArgumentException(message);
  }
}

class Thing
{
  public byte a { get; set; }
  public UInt16 b { get; set; }
  public UInt32 c { get; set; }
  public byte d { get; set; }
  public void Read(List<byte> data)
  {
    a = a.Read(data);
    b = b.Read(data);
    c = c.Read(data);
    d = d.Read(data);
  }
}

这并没有提供绝对的方法来避免编码错误,而是少做,因为我们可以很容易地看到与我们操作的变量的匹配,就像使用字符串方法修改相同的字符串时一样。

测试

var list = new List<byte> { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };

var instance = new Thing();

instance.Read(list);

输出

Read byte
Read UInt16
Read Uint32
Read byte

推荐阅读