我试图编写一个通用方法来执行从long到其他类型的未经检查的赋值。这是简化版本:
private static void AssignHex<T>(string hex, out T val) where T : struct
{
if (long.TryParse(hex, NumberStyles.AllowHexSpecifier, null, out long lval))
{
unchecked
{
val = (T)Convert.ChangeType(lval, typeof(T));
}
}
else
{
val = default(T);
}
}
除了输入字符串&#34; FFFFFFFF&#34;并输入int,我希望得到-1,而不是溢出异常。等效的非泛型方法可以正常工作:
private static void AssignHex2(string hex, out int val)
{
if (long.TryParse(hex, NumberStyles.AllowHexSpecifier, null, out long lval))
{
unchecked
{
val = (int)lval;
}
}
else
{
val = default(int);
}
}
我可以简单地编写非泛型,但令我困扰的是我无法使用通用版本。任何解决方案?
答案 0 :(得分:4)
尽管System.Convert.ChangeType
非常方便很多次,但你不能在你的场景中使用它。十进制的FFFFFFFF
是4294967295,无法在int
类型中表示,转换失败。抛出的特定代码是this(如果long长于最大int
值则检查。)
如果您需要此功能,则必须手动编写与System.Convert.ChangeType
- if
语句中类似的代码,其中包含unchecked
块中包含的适当强制转换的不同可能类型。或者根本不使用泛型,并且对您感兴趣的每种类型都有重载。
编辑:最好完全删除unchecked
块并将十六进制值直接解析为适当的类型,而不是先将其解析为long。这样,您将直接将其解析为期望值,并在值超出范围时收到错误,而不是仅使用unchecked
块静默忽略剩余位。
EDIT2:使用two's complement表示负数。简而言之,您可以通过翻转代表正数并添加1的所有位来从正数得到负数。这意味着负数的二进制或十六进制表示取决于为数字分配的位数。因此对于8位数(sbyte
)-1是0xFF,对于16位数(short
)是0xFFFF,对于32位数(int
)是0xFFFFFFFF和64位数( long
)是0xFFFFFFFFFFFFFFFF。由于您将十六进制值0xFFFFFFFF解析为long
,因此您不是-1,因为您实际上正在解析0x0000000FFFFFFFF。你的unchecked
块的作用是,当转换为较低的精度数时,它将只需要较低精度类型所需的位数,并在不进行任何检查的情况下丢弃其余部分。想象一下,你有0XF0000000FFFFFFFF。如果你解析这个,你得到~1 quintillion但是未经检查的强制转换为int
你会得到-1,完全忽略最重要的4位。
答案 1 :(得分:0)
确定。涉及到一些痛苦,但答案是:
private static bool AssignHex4<T>(string hex, out T val)
{
Type t = typeof(T);
MethodInfo mi = t.GetMethod("TryParse", new Type[] { typeof(string), typeof(NumberStyles), typeof(IFormatProvider), typeof(T).MakeByRefType()});
if (mi != null)
{
object[] parameters = new object[] {hex, NumberStyles.AllowHexSpecifier, null, null};
object result = mi.Invoke(null, parameters);
if ((bool) result)
{
val = (T)parameters[3];
return true;
}
}
val = default(T);
return false;
}
一些SO答案需要大声宣传,这些答案有助于将它们结合在一起:
MethodInfo.Invoke with out Parameter
Specifying out params for Type.GetMethod
我承认这不是一个特别优雅的答案,但我认为它是全面的,而这正是我所寻找的。 p>
考虑...
AssignHex4("FF", out byte r1);
AssignHex4("FFFF", out short r2);
AssignHex4("FFFFFFFF", out int r3);
AssignHex4("FFFFFFFFFFFFFFFF", out long r4);
AssignHex4("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", out BigInteger r5);
Console.WriteLine("Convert in reflection function returns:" + r1 + ", " + r2 + ", " + r3 + ", " + r4 + ", " + r5);
导致......
Convert in reflection function returns:255, -1, -1, -1, -1