我有一个简单的类,用于存储缩放的整数值 使用成员变量“ scaled_value”(长整数)和“ scale_factor”。
我有一个用小数填充新类实例的构造函数 值(尽管我认为值类型无关紧要)。 分配给“ scaled_value”插槽出现...不会发生。 我已经为它插入了常量1的显式赋值。 下面的Debug.Assert失败...并且scaled_value为零。
在即时窗口的断言中断中,我可以使用赋值/检查“ scale_factor”进行检查/设置;它会随着我的设置而改变。
我可以检查“ scaled_value”。始终为零。我可以输入 立即窗口执行给它的赋值,但是它的值 不会改变。
我将Visual Studio 2017与C#2017一起使用。
此插槽的魔力是什么?
public class ScaledLong : Base // handles scaled-by-power-of-ten long numbers
// intended to support equivalent of fast decimal arithmetic while hiding scale factors from user
{
public long scaled_value; // up to log10_MaxLong digits of decimal precision
public sbyte scale_factor; // power of ten representing location of decimal point range -21..+21. Set by constructor AND NEVER CHANGED.
public byte byte_size; // holds size of value in underlying memory array
string format_string;
<other constructors with same arguments except last value type>
public ScaledLong(sbyte sf, byte size, string format, decimal initial_value)
{
scale_factor = sf;
byte_size = size;
format_string = format;
decimal temp;
sbyte exponent;
{ // rip exponent out of decimal value leaving behind an integer;
_decimal_structure.value = initial_value;
exponent = (sbyte)_decimal_structure.Exponent;
_decimal_structure.Exponent = 0; // now decimal value is integral
temp = _decimal_structure.value;
}
sbyte sfDelta = (sbyte)(sf - exponent);
if (sfDelta >= 0)
{ // sfDelta > 0
this.scaled_value = 1;
Debug.Assert(scaled_value == 1);
scaled_value = (long)Math.Truncate(temp * DecimalTenToPower[sfDelta]);
}
else
{
temp = Math.Truncate(temp / DecimalHalfTenToPower[-sfDelta]);
temp += (temp % 2); /// this can overflow for value at very top of range, not worth fixing; note: this works for both + and- numbers (?)
scaled_value = (long)(temp / 2); // final result
}
}
答案 0 :(得分:0)
最大的难题通常具有最愚蠢的基础。这是一个意外副作用的课程。
我是通过思考来发现这一点的,不知道成员如何以意想不到的方式进行修改。在阅读@mjwills评论之前,我已经找到了解决方案,但是他绝对是在嗅探正确的事情。
我遗漏的(当然!)是我刚刚为该类编写了一个ToString()方法,但尚未调试。我为什么要忽略它?因为它显然不会影响任何事情,所以它不会成为问题的一部分。
Bzzzzt!它使用成员变量作为暂存器并将其清零(有副作用);显然是意想不到的。
这意味着当代码刚刚运行时,不会调用ToString(),并且成员变量DOES会被正确修改。 (我什至对“ Set”例程进行了单元测试,检查了所有内容,并且它们都正常工作。)
但是,当您调试时...。调试器可以(并且在这种情况下也可以)显示局部变量。为此,它显然将调用ToString()以获取一个不错的可显示值。因此,单步执行会导致调用ToSTring(),并且它的多用临时变量分配在每次调用后都将插槽清零。
所以这不是让我难过的二传手。可以说是吸气剂。 (您需要的时候FORTRAN的PURE关键字在哪里?)
爱因斯坦讨厌远距离的诡异动作。程序员讨厌远距离的怪异副作用。
有人对调试器在类的构造函数尚未完成的类上调用ToString()的想法感到惊讶。给定构造函数未完成,ToString可以信任有关类状态的哪些断言?我认为MS调试器应该是固定的。这样,我本可以花时间调试ToString而不是追求它。
感谢您提出我的问题。它使我得到了答案。