【问题标题】:C# Initialization Confusion!C#初始化混乱!
【发布时间】:2009-05-07 19:37:44
【问题描述】:
int?  test;
try
{
    test = (int?) Int32.Parse ("7");
} catch {}

if (test == null)
     Console.WriteLine("test is null!");
else
     Console.WriteLine("test = {0}", test);

我有一些代码与此非常相似,实际上是相同的想法...创建一个变量,尝试对其进行初始化,然后测试初始化​​是否成功。

Visual Studios 给我一个错误提示“使用未分配的局部变量 'test'”,这有点烦人,可以通过将第一行设置为:

int?  test = null;

但我很好奇这两行之间的区别是什么,因为编译器似乎真的很在意。据我所知,这两行代码的作用相同。

【问题讨论】:

  • OT,但是 FWIW... 你可能想看看 TryParse()
  • 我实际上并没有使用此代码,这只是我似乎偶尔会遇到的一个场景。

标签: c# syntax null


【解决方案1】:

问题是catch块。编译器必须假定 Int32.Parse 代码可以抛出并因此命中您的 catch 块。在这种情况下, Int32.Parse 行没有完成,因此 test 永远不会被赋值。这意味着“if”行正在尝试使用未初始化的值。

你可以解决这个问题

  1. 在 catch 块中为测试分配一个值
  2. 在方法开始时将其初始化为 null

【讨论】:

    【解决方案2】:

    你混淆了什么是变量声明和什么是变量初始化之间的区别

    int?  test;
    

    简单地说你有一个名为 test 的变量,它是一个可以为空的 int

    但是

    int?  test = null;
    

    表示您有一个名为 test 的变量,它是一个可为空的 int 且其值为 null

    在 VB 中没有区别,但在 c# 中却有区别。这就是编译器抱怨的原因,因为如果您的 try 块中出现问题,那么您的测试变量将永远不会被初始化。

    【讨论】:

      【解决方案3】:

      您可以避免 (int?) 强制转换,为“= null”字符串节省 7 个字节:)

      test = Int32.Parse ("7");
      

      【讨论】:

        【解决方案4】:

        对于本地定义的变量(在方法或属性内,而不是直接在类内),总是会出现这种错误。尽管编译器不需要生成此错误以工作这一事实仍然存在,但它这样做专门用于帮助您识别潜在的意外结果总是分配你的变量。 (如果我错了,请有人纠正我,但至少某些以前版本的 C# 编译器在某些/所有情况下都没有检查未分配的变量。)

        等效地(而不是在声明中分配test = null),您可以通过在catch 块中分配test = null 来消除错误,因为这意味着无论代码采用什么路径,都会分配变量test。但是,我认为您所说的解决方案(在声明中分配给 null )是正确的解决方案 - 您会经常在包含很多分支的 C# 代码中看到它(通过 try-catch 语句、if 语句或其他任何东西) - 老实说,它只是帮助您了解分配变量的内容和时间,即使它看起来像是一个小麻烦。

        【讨论】:

        • 这个答案大部分是错误的,尽管它得出了一个正确的结论。首先,可空类型是值类型,而不是引用类型。其次,引用类型不需要赋值。 局部变量在使用前需要赋值。第三,无法在编译器中关闭该错误。结论——局部变量在使用前必须明确赋值——是正确的,但结论是通过错误的推理得出的。
        • @eric-lippert:是的,当我写这篇文章时,我的大脑显然没有工作。我试图区分何时和何时不需要在使用它们之前分配变量(正确的条件是 all 局部变量,而不是实例/静态变量)。无论如何,我的大部分解释都与主要论点有点相切,所以我关于生成错误以帮助您识别可能的问题来源的观点仍然正确。
        • 我的意思是,这个问题与“引用类型与值类型”完全无关,所以别提了。问题与“局部变量与任何其他类型的变量”有关。在读取其内容之前,所有变量都必须明确赋值。但是在 C# 中的所有类型的变量中,只有局部变量被认为是最初未分配的
        • 是的,您的结论是,明确的分配检查功能可以帮助您在分配之前发现使用本地的常见错误是正确的。
        • @Meiscooldude:请至少重新阅读我的帖子以现在收集正确的信息 - 对最初的一些垃圾感到抱歉。 (另外,如果你现在接受另一个答案,我一点也不生气 - 它们现在都是正确的,所以这取决于你。)
        【解决方案5】:

        他们做同样的事情,你是正确的,但是变量需要显式分配 null 以消除“未分配值”错误,如果您希望 null 被视为故意的“未设置”变量,不会抛出警告。除此之外,Jaredpar 的答案是正确的。

        【讨论】:

          【解决方案6】:

          我相信这种风格更干净:

          try
          {
              int test = Int32.Parse("7");
              Console.WriteLine("Success!");
              // add return statement for successful execution here, if any
          }
          catch
          {
              Console.WriteLine("Disaster!");
              // other return statement here, if any
          }
          

          至于编译器错误:任何本地字段必须在读取之前在代码路径上显式初始化。不初始化本地字段是一个常见错误,这就是为什么它是 C# 中的错误。 C/C++ 只对此发出警告,如果它没有初始化并且值反映了调用堆栈上已经存在的字节,它可能会产生 *funny* 结果。

          我只能推测这一点,但这可能是显式初始化本地字段的性能方面,与类字段相反:实例化对象时,运行时初始化对象内存流一次的成本较低,但是在每个方法调用上多次初始化一个本地字段是多余的。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2015-11-30
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-06-28
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多