为什么Int32.TryParse在无法转换时会重置输出参数?

10

如果我运行这段C#代码

int realInt = 3;  
string foo = "bar";  
Int32.TryParse(foo, out realInt); 

Console.WriteLine(realInt);  
Console.Read();

我得到了0。我想知道为什么!因为我找不到任何原因。这迫使我为每个解析创建临时变量。所以,请宇宙中伟大的程序员们,启发我吧!

9个回答

34

应该使用 "out",而不是 "ref"。在方法内部,为满足 "out" 的含义,它必须将其赋值(而不先读取)。

实际上,“out”是一项语言规定(而非框架规定),因此,托管 C++ 实现可能会忽略此规定......但遵循此规定更加一致。

事实上,如果该方法返回 false,则您根本不应查看该值;直到下一次分配之前,将其视为垃圾。虽然它被声明为返回 0,但这很少有用。


另外,如果它没有这样做(即保留该值),那么这将打印什么:

int i;
int.TryParse("gibber", out i);
Console.WriteLine(i);

这是完全有效的C#代码...那么它会输出什么?


2
为什么是这样的解释是为了让您断言在TryParse调用之后的任何代码中变量都将始终被设置,即使变量在代码中之前没有初始化(因此编译器在您在TryParse调用后使用变量时不会抛出错误;请尝试使用使用ref关键字的函数执行相同的操作。) - Blixt

7

Int32.TryParse方法 (String, Int32) 文档 中提到:

将数字的字符串表示转换为其 32 位有符号整数等效项。返回值指示转换是否成功。

result

类型:System.Int32

当此方法返回时,如果转换成功,则包含与 s 参数中包含的数字等效的 32 位有符号整数值,如果转换失败,则为零。 如果 s 参数是 null 引用(Visual Basic 中的 Nothing),格式不正确或表示小于 MinValue 或大于 MaxValue 的数字,则转换失败。 此参数未初始化传递。


4
因为参数是输出参数,所以在声明 realInt 时不必初始化,因为编译器可以看到你将其传递给一个方法,该方法保证将其设置为某个值(由于 "out")。
现在,因为它是一个输出参数,TryParse 被要求将其设置为某个值。 它将其设置为 0,因为在大多数情况下,这是 C# 中 int 的默认值。
你也可以写成:
int realInt;
string foo="bar";
if(int.TryParse(foo,out realInt)==false)
{
  realInt=3;
}

1
更好的写法是在TryParse的开头加上一个!运算符,即如果(!Int32.TryParse(foo,out realInt)) - James

2

这是“out”合同的工作原理。每当您将一个out参数传递给函数时,函数负责初始化它。


1

关于 Int32.TryParse 的 MSDN 文档指出,如果转换失败,则结果将始终返回 0。

通常情况下,您应该使用临时结果变量,例如:

int value;
bool succeeded = Int32.TryParse("astring", out value);
if (succeeded)
{
  // use value in some way
}

或者你可以将整个方法用if语句包装起来

int value;
if (Int32.TryParse("astring", out value))
{
  // use value in some way
}

个人而言,我认为后者是更好的选择。


1
public static class IntHelper
{
    public static bool TryParse(string s, ref int outValue)
    {
        int newValue;
        bool ret = int.TryParse(s, out newValue);
        if (ret) outValue = newValue;
        return ret;
    }
}

0
因为(至少在C#中),接受一个或多个out参数的方法必须保证将值写回这些参数中。这样你就不需要在一个方法中初始化本地字段再将其作为out参数传递给另一个方法。

0

我猜这是C#规范的一部分:

10.5.1.3 输出参数 ... 在方法内部,就像本地变量一样,输出参数最初被认为是未赋值的,在使用其值之前必须明确赋值。

方法的每个输出参数在方法返回之前必须明确赋值。

如果是这种情况,您不应该依赖于结果值。


0

由于TryParse的第二个参数是一个out参数,所以TryParse方法被强制初始化该参数。如果该参数是ref而不是out,则可以获得所需的行为。然而,由于TryParse方法只需要输出一个数字而不需要获取任何数字作为输入,因此out是参数的正确选择。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接