【问题标题】:C# Automatic Properties - Still null after +=?C# 自动属性 ​​- 在 += 之后仍然为空?
【发布时间】:2009-08-26 14:51:09
【问题描述】:

这对我来说似乎是一个错误......

我接受这样定义的自动属性:

public decimal? Total { get; set; }

第一次访问时将为空。它们还没有被初始化,所以它们当然是空的。

但是,即使在通过 += 设置它们的值之后,这个小数?仍然为空。所以之后:

Total += 8;

总计仍为空。这怎么可能是正确的?我知道它正在执行 (null + 8),但似乎很奇怪它没有接收到这意味着它应该设置为 8...

附录:

我在我的问题中提出了“null + 8”点 - 但请注意它适用于字符串。因此,它执行 null + "hello" 就好了,并返回 "hello"。因此,在幕后,它是将字符串初始化为值为“hello”的字符串对象。其他类型 IMO 的行为应该相同。可能是因为字符串可以接受 null 作为值,但 null 字符串仍然不是初始化对象,对吗?

也许只是因为字符串不能为空......

【问题讨论】:

  • "它们还没有被初始化,所以它们当然是空的。"这是你困惑的症结所在。在这种情况下,属性最初会自动分配给 null。你是从一个谎言中推断出来的:该属性是未分配的。 该属性是最初分配的。 C# 中没有“未分配的属性”之类的东西。
  • 有趣的区别。同样有趣的是,您可以找到数千个将“初始化为 null”的值称为“未初始化”的示例。所以也许这是一个普遍的误解。我很好奇的一件事 - 如果我们有这个问题,我们不想让“null + 8 = 8”或“null && true == true”,为什么当这些类型时没有抛出异常事情完成了吗?似乎这样可以防止一些难以调试的错误。

标签: c# initialization automatic-properties


【解决方案1】:
public decimal? Total { get; set; }

null 视为“未知值”。如果你有 unknown 数量的东西,然后再添加 8 个,那么你现在有多少个?

答案:未知。

可空变量的操作

种情况,对未知值的操作会给你已知的结果。

public bool? State { get; set; }

以下语句具有已知个解决方案,即使它们包含未知值:

State = null;
nextState = State & false;         // always equals false
nextState = State & true;          // still unknown (null)

nextState = State | true;          // always true
nextState = State | false;         // still unknown (null)

看到图案了吗?

当然,如果你想要Totalnull时等于(等于)0,你可以使用空合并运算符并写像这样:

Total = (Total ?? 0) + 8;

这将在您的等式中使用 Total 的值除非它是 null,在这种情况下它将使用值 0。

【讨论】:

  • 是的,我想这是有道理的。只是看起来很时髦。 :)
  • Total = (Total ?? 0) + 8; 在 .NET 版本 4.5+ 中可以重写为 Total = Total.GetValueOrDefault(0) + 8;
【解决方案2】:
Null + 8 = Null

您需要先将其设置为零。

【讨论】:

  • 是的,我知道这就是解决方案,我只是觉得这很愚蠢。 :)
  • 因为它违反直觉,至少对我来说是这样。如果它是我的编译器,我会做出这样的假设(特别是对于像 automatic 属性这样的东西),如果你有一个未初始化的值并且你向它添加一些东西,它只会拾取附加值.但是,也许在某些情况下,这种假设会导致问题,谁知道呢。
  • 你确实 NOT 有一个未初始化的值。你有一个初始化为 null 的值。
【解决方案3】:

null 表示未知值,

unknown value + known value = still unknown value

【讨论】:

  • 我理解 null 是什么,但在我看来,null + 8 等于 8 是一个安全的假设。但是,我想我错了。 :)
  • 你确实错了:) 如果null 等于0,那么拥有null 的意义何在?请注意,如果您将属性定义为不可为空的类型(删除 ? 符号),它将被赋予十进制类型的默认值,AFAIK 为 0,您将能够使用您的 += 8 代码。跨度>
  • 哈哈 - :) 是的,我之前注意到 auto-props 的默认值。我并不是说 null 应该等于 0,只是如果您有一个初始化值并将其添加到 null,那么该字段只会获取初始化值对我来说是有意义的。
  • 您真的希望它像这样工作吗?让我给你一个真实的例子,为什么这是错误的:假设你的钱包里有一些钱(但是你不确定有多少,可以是 20 美元,可以是 2000 美元,这是我们的null)。现在有人给你额外的500美元。如果这能像您描述的那样有效,那么您现在的总资金应该是 500 美元。我怀疑你会喜欢那个:)
  • 我知道你要去哪里,但我不确定你的例子是否符合 null 的真正含义。我的意思是,不是 null 代表一些“未知值”,例如“X”。如果有人告诉我我有 X 美元,而我加了 500 美元,是的,我不希望得到 500 美元。但我不认为 null 代表“X”,它代表(正如他们在 VB 中所说),Nothing。因此,并不是有一些未知的内存位置 可能 持有一个值 - null 显然什么都不是。所以在那种情况下,如果我什么都没有,我加了 500 美元,我可以有 500 美元。我们当然是在分裂头发。
【解决方案4】:

这是一个在第一次调用时初始化它并在之后递增它的单行代码:

    public void InitializeOrIncrement(decimal value)
    {
        // if Total is null then initialize, otherwise increment
        Total = (Total == null) ? value : Total + value;
    }

    public decimal? Total { get; set; }

【讨论】:

    【解决方案5】:

    来自MSDN

    当您与 可为空的类型,如果其中之一的值 可以为空的类型是 null 并且 其他不是,所有比较都评估 为假,除了 != (不等于)。它 重要的是不要假设 因为特定的比较 返回false,相反的情况 返回真。

    所以,它按预期工作。

    【讨论】:

      【解决方案6】:

      我知道这样做是有意义的

      public decimal? Total { get; set; }
      
      Total = (Total ?? 0) + 8;
      

      但是这样做会不会更容易:

      public decimal Total { get; set; }
      

      Total的初始值为0

      【讨论】:

      • 是的,这实际上是我最终将代码更改为的内容。对于一个运行总计,如果您考虑一下,将总计设为 null 真的没有意义。添加的项目可能为空是有道理的,但总数可能总是 >= 0。不过讨论很有趣。
      【解决方案7】:

      正如其他人指出的那样,null 不等于零。尽管从长远来看,将空整数默认为零似乎更方便,但它可能会产生奇怪的结果,直到为时已晚才发现。

      举个简单的例子,假设您的一个数据馈送失败并使用空值填充您的结果集。您的计算会将空值视为零并继续产生结果。由于数字仍在出现,即使它们可能是错误的,您也可能永远不会注意到出现严重错误。

      【讨论】:

        【解决方案8】:

        设置Total的值只是

        Total = 8;
        

        我建议阅读 Nullable Types 以了解它们的工作原理。您可以使用HasValue 来检查该属性是否具有值。

        来自MSDN

        运营商

        预定义的一元和二元 运算符和任何用户定义的 存在于值类型的运算符 也可以由可为空的类型使用。 这些运算符产生一个空值 如果操作数为空;否则, 运算符使用包含的值 计算结果。例如:

        int? a = 10;
        int? b = null;
        
        a++;         // Increment by 1, now a is 11.
        a = a * 10;  // Multiply by 10, now a is 110.
        a = a + b;   // Add b, now a is null.
        

        【讨论】:

        • 谢谢。我经常使用可空类型,并且在自动属性初始化方面遇到了很多问题,但从不费心问为什么。我想这是有道理的,虽然我不知道我是否会那样做......
        • 有一个很好的部分介绍了 C# 中的 Nullable Types in Depth,其他有趣的细节主要是 C#3,还有一点 C#1 和更多关于 C#2。确实是一本好书。
        • 可空类型的整个想法是您可以将空值分配给值类型:)
        【解决方案9】:

        Null 不等于零。零加八等于八……但零加八?始终为空。就像无限加上任何东西仍然是无限 - 它是未定义的。

        您会发现 null 普遍适用。每个数据库(至少我曾经使用过的)都会给你相同的结果。

        【讨论】:

          【解决方案10】:

          公用小数点?总{得到;放; }

          这样的东西会起作用吗?如果尚未设置值,则进行某种自动初始化。

          public decimal? Total
          {
            get { return this.totalValue;}
            set
            { 
               if(totalValue == null) { this.totalValue = 0;}
               this.totalValue = value;
            }
          }
          
          private decimal? totalValue;
          

          【讨论】:

          • ...但是如果您不使用自动实现的属性,那么为什么不将您的支持字段作为其声明的一部分进行初始化呢? private decimal? totalValue = 0;
          • 是的,让我们面对现实吧,我使用自动属性的唯一原因是懒于打字。 (不是对象输入 - 只是手指输入!)如果我要将它拆分出来,我会将其默认为 0。
          • Yooder,因为他可能不希望该值为 0,他可能希望它为 null...罗伯特,实际上不,如果有人将 Total 设置为 null,它将被设置为 0,并且然后在这种情况下重置为空,因为“值”将为空。 0 只是用作惰性初始化器。
          猜你喜欢
          • 1970-01-01
          • 2011-05-09
          • 1970-01-01
          • 2011-05-02
          • 1970-01-01
          • 2021-06-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多