构造函数中的C#分配给成员...不会更改它

时间:2019-02-26 18:50:18

标签: c# constructor variable-assignment member

我有一个简单的类,用于存储缩放的整数值 使用成员变量“ 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
     }

  }

1 个答案:

答案 0 :(得分:0)

最大的难题通常具有最愚蠢的基础。这是一个意外副作用的课程。

我是通过思考来发现这一点的,不知道成员如何以意想不到的方式进行修改。在阅读@mjwills评论之前,我已经找到了解决方案,但是他绝对是在嗅探正确的事情。

我遗漏的(当然!)是我刚刚为该类编写了一个ToString()方法,但尚未调试。我为什么要忽略它?因为它显然不会影响任何事情,所以它不会成为问题的一部分。

Bzzzzt!它使用成员变量作为暂存器并将其清零(有副作用);显然是意想不到的。

这意味着当代码刚刚运行时,不会调用ToString(),并且成员变量DOES会被正确修改。 (我什至对“ Set”例程进行了单元测试,检查了所有内容,并且它们都正常工作。)

但是,当您调试时...。调试器可以(并且在这种情况下也可以)显示局部变量。为此,它显然将调用ToString()以获取一个不错的可显示值。因此,单步执行会导致调用ToSTring(),并且它的多用临时变量分配在每次调用后都将插槽清零。

所以这不是让我难过的二传手。可以说是吸气剂。 (您需要的时候FORTRAN的PURE关键字在哪里?)

爱因斯坦讨厌远距离的诡异动作。程序员讨厌远距离的怪异副作用。

有人对调试器在类的构造函数尚未完成的类上调用ToString()的想法感到惊讶。给定构造函数未完成,ToString可以信任有关类状态的哪些断言?我认为MS调试器应该是固定的。这样,我本可以花时间调试ToString而不是追求它。

感谢您提出我的问题。它使我得到了答案。