【问题标题】:int.TryParse overwrites the value of the integer passed as an out parameterint.TryParse 覆盖作为输出参数传递的整数的值
【发布时间】:2013-05-22 07:24:35
【问题描述】:

我有这个代码...

var i = int.MinValue;
var s = string.Empty;
int.TryParse(s, out i);

TryParse 语句之后,i 变量中的值被覆盖(as zero),我之前的值丢失了。

这是一个错误吗?如果否,是否有任何实现细节说明为什么需要重新初始化作为out 参数传递的变量

【问题讨论】:

  • 你不需要初始化i,将第一行替换为int i;,代码应该仍然可以工作。
  • 当我给 var i=100; 时会发生什么int.TryParse("012",out i); ?是否需要为 i 赋值?解释

标签: .net c#-4.0 .net-4.0


【解决方案1】:

out 的全部意义在于它保证(嗯,至少在 C# 级别……而不是 IL 级别)覆盖此值。这样做的目的是避免不必要的分配,同时允许“明确分配”。例如:

int i; // note: not assigned
var s = string.Empty;

// here "i" is not "definitely assigned"
int.TryParse(s, out i);
// here "i" is "definitely assigned"

想法是你使用返回值,例如:

if(int.TryParse(s, out i)) {
   // here "i" makes sense; feel free to use it
} else {
   // here you shouldn't use the value of "i"
}

在您的具体情况下,您可以重新订购:

if(!int.TryParse(s, out i)) i = int.MinValue;

特别要注意(至少在 C# 中)方法必须分配值,并且不能使用传入的值;例如:

static void Foo(out int i) {
    return; // error: hasn't assigned to i
}
static void Bar(out int i) {
    int j = i; // error: cannot read from "i" until Bar has assigned a value
    i = j;
}
static void Baz(out int i) {
    i = 0; // note that after this assignment, code in Baz can read from "i"
}

对比ref;当传递ref 值时,必须在调用者处明确分配。方法本身可能会或可能不会查看传入的值(根据它的选择),并且可能会或可能不会分配一个新值(根据它的选择)。例如:

int i;
SomeMethod(ref i); // illegal - "i" is not definitely assigned

int i = 0;
SomeMethod(ref i); // legal

和:

static void Foo(ref int i) {
    return; // perfectly legal to not look at "i" and/or not assign "i"
}
static void Foo(ref int i) {
    i = i + 1; // perfectly legal to look at "i" and/or assign "i"
}

【讨论】:

  • 我将选择您的回答作为答案,因为对问题的清楚解释以及使用 out 的示例。请在您的答案中添加对ref 的比较,因为我认为如果变量作为ref 参数传递,那么它预期会被初始化......
【解决方案2】:

这不是错误,如果转换失败,将返回零。在这种情况下,函数的返回值为 false。

当此方法返回时,包含 32 位有符号整数值 相当于s中包含的数字,如果转换成功, 如果转换失败,则为零。如果 s 转换失败 参数为空、格式不正确或表示 小于 MinValue 或大于 MaxValue 的数字。这个参数是 通过未初始化。

http://msdn.microsoft.com/en-us/library/f02979c7.aspx

【讨论】:

    【解决方案3】:

    out (C# Reference)

    虽然作为输出参数传递的变量不需要初始化 在被传递之前,调用方法需要分配一个 方法返回之前的值

    Int32.Parsedefault(int) 初始化它,它是零。

    当此方法返回时,如果转换成功,则包含与 s 中包含的数字等效的 32 位带符号整数值,如果转换失败则为零

    【讨论】:

      【解决方案4】:

      这不是错误,因为它是一个输出参数。作为练习,尝试编写不设置 out 参数值的 C#。 (提示:这是不可能的)因此,您观察到的结果是唯一合乎逻辑的结果 - out 变量没有“重新初始化”,它只是简单地初始化。

      如果 TryParse 被编写为采用 ref int,那么您想要的就是可能的。我个人认为 int 在这里更好。

      【讨论】:

        【解决方案5】:

        不,如果您将变量的值设置为例如“3”,这不是错误

        var s = "3";
        

        你会得到 i 的值等于 3

        如果你设置 string.Empty 它将为零,这是默认实现

        你可以看看反编译的实现代码

        internal static unsafe bool TryParseInt32(string s, NumberStyles style, NumberFormatInfo info, out int result)
        {
          byte* stackBuffer = stackalloc byte[114];
          Number.NumberBuffer number = new Number.NumberBuffer(stackBuffer);
          result = 0;
          if (!Number.TryStringToNumber(s, style, ref number, info, false))
            return false;
          if ((style & NumberStyles.AllowHexSpecifier) != NumberStyles.None)
          {
            if (!Number.HexNumberToInt32(ref number, ref result))
              return false;
          }
          else if (!Number.NumberToInt32(ref number, ref result))
            return false;
          return true;
        }
        

        结果设置为0;

        【讨论】:

          猜你喜欢
          • 2015-12-20
          • 1970-01-01
          • 1970-01-01
          • 2016-05-27
          • 1970-01-01
          • 2011-02-13
          • 2016-05-06
          • 2020-09-04
          • 1970-01-01
          相关资源
          最近更新 更多