扩展Jon Skeet对This Previous Question的回答。 Skeet没有解决负值和两个补码值进入图片时发生的故障。
简而言之,我想将任何简单类型(保存在未知的盒装object
中)转换为System.UInt64
,以便我可以使用基础二进制表示。
为什么我要这样做?请参阅底部的说明。
以下示例显示了Convert.ToInt64(object)
和Convert.ToUInt64(object)
都中断(OverflowException
)的情况。
以下OverflowExceptions
只有两个原因:
-10UL
时, Int64
会导致异常,因为负值会转换为0xfffffffffffffff6
(在未经检查的上下文中),这是一个大于{{1的正数}}。 我希望将其转换为Int64.MaxValue
。
转换为-10L
时,包含负值的签名类型会导致异常,因为UInt64
小于-10
。 我希望这些转换为真正的二进制补码值(UInt64.MinValue
)。无符号类型不能真正保持负值0xffffffffffffffff6
,因为它被转换为二进制补码在未经检查的背景下;因此,无符号类型不会发生异常。
kludge解决方案似乎是转换为-10
,然后是未经检查的转换为Int64
。此中间强制转换会更容易,因为在直接转换为UInt64
时,只有一个实例导致Int64
异常而八个失败。
注意:该示例仅使用UInt64
上下文,以便在装箱期间将负值强制为无符号类型(这会创建一个正的二进制补码等效值)。此unchecked
上下文不是手头问题的一部分。
unchecked
为什么我希望能够将所有这些值类型转换为using System;
enum DumbEnum { Negative = -10, Positive = 10 };
class Test
{
static void Main()
{
unchecked
{
Check((sbyte)10);
Check((byte)10);
Check((short)10);
Check((ushort)10);
Check((int)10);
Check((uint)10);
Check((long)10);
Check((ulong)10);
Check((char)'\u000a');
Check((float)10.1);
Check((double)10.1);
Check((bool)true);
Check((decimal)10);
Check((DumbEnum)DumbEnum.Positive);
Check((sbyte)-10);
Check((byte)-10);
Check((short)-10);
Check((ushort)-10);
Check((int)-10);
Check((uint)-10);
Check((long)-10);
//Check((ulong)-10); // OverflowException
Check((float)-10);
Check((double)-10);
Check((bool)false);
Check((decimal)-10);
Check((DumbEnum)DumbEnum.Negative);
CheckU((sbyte)10);
CheckU((byte)10);
CheckU((short)10);
CheckU((ushort)10);
CheckU((int)10);
CheckU((uint)10);
CheckU((long)10);
CheckU((ulong)10);
CheckU((char)'\u000a');
CheckU((float)10.1);
CheckU((double)10.1);
CheckU((bool)true);
CheckU((decimal)10);
CheckU((DumbEnum)DumbEnum.Positive);
//CheckU((sbyte)-10); // OverflowException
CheckU((byte)-10);
//CheckU((short)-10); // OverflowException
CheckU((ushort)-10);
//CheckU((int)-10); // OverflowException
CheckU((uint)-10);
//CheckU((long)-10); // OverflowException
CheckU((ulong)-10);
//CheckU((float)-10.1); // OverflowException
//CheckU((double)-10.1); // OverflowException
CheckU((bool)false);
//CheckU((decimal)-10); // OverflowException
//CheckU((DumbEnum)DumbEnum.Negative); // OverflowException
}
}
static void Check(object o)
{
Console.WriteLine("Type {0} converted to Int64: {1}",
o.GetType().Name, Convert.ToInt64(o));
}
static void CheckU(object o)
{
Console.WriteLine("Type {0} converted to UInt64: {1}",
o.GetType().Name, Convert.ToUInt64(o));
}
}
?因为我编写了一个类库,它将结构或类转换为打包为单个UInt64
值的位字段。
示例:考虑每个IP包头中的UInt64
字段,该字段由许多二进制位字段组成:
使用我的类库,我可以创建一个表示DiffServ字段的结构。我创建了一个DiffServ
,它指示哪些位属于二进制表示中的位置:
BitFieldAttribute
我的类库然后可以将此结构的实例转换为正确的二进制表示形式:
struct DiffServ : IBitField
{
[BitField(3,0)]
public PrecedenceLevel Precedence;
[BitField(1,3)]
public bool Delay;
[BitField(1,4)]
public bool Throughput;
[BitField(1,5)]
public bool Reliability;
[BitField(1,6)]
public bool MonetaryCost;
}
enum PrecedenceLevel
{
Routine, Priority, Immediate, Flash, FlashOverride, CriticEcp,
InternetworkControl, NetworkControl
}
为此,我的类库会查找用// Create an arbitrary DiffServe instance.
DiffServ ds = new DiffServ();
ds.Precedence = PrecedenceLevel.Immediate;
ds.Throughput = true;
ds.Reliability = true;
// Convert struct to value.
long dsValue = ds.Pack();
// Create struct from value.
DiffServ ds2 = Unpack<DiffServ>(0x66);
修饰的字段/属性。获取和设置成员检索包含盒装值类型(int,bool,enum等)的对象。因此,我需要取消设置任何值类型并将其转换为它的简单二进制表示,以便可以提取和打包这些位成BitFieldAttribute
值。
答案 0 :(得分:2)
我将发布我最好的解决方案作为群众的饲料。
当取消装箱float, double, decimal
中保存的未知简单值类型时,这些转换会消除所有异常(非常大的object o
值除外,这些值不适合64位整数):
long l = o is ulong ? (long)(ulong)o : Convert.ToInt64(o));
ulong u = o is ulong ? (ulong)o : (ulong)Convert.ToInt64(o));
欢迎任何改进。