另一个“使用未分配的局部变量'无论''问题

时间:2011-08-30 09:36:21

标签: c# compiler-errors language-design

这是我一段时间以来一直想知道的事情。我在标题中浏览了一系列包含错误的问题,但找不到解释此案例的问题。

首先看一下这个例子:

private void test() {
    string errorMessage;
    bool isOK = SomeClassWithBusinessRules.VerifySomeStuff(idOfStuffToVerify, ref errorMessage);
    if (!isOK)
        throw new BusinessException(errorMessage ?? "Some error occured.");
}

如果你编译它,编译器会抱怨这条消息:

  

错误2使用未分配的局部变量'errorMessage'

将变量初始值设定项更改为null会使其消失。

这将编译:

private void test() {
    string errorMessage = null;
    bool isOK = SomeClassWithBusinessRules.VerifySomeStuff(idOfStuffToVerify, ref errorMessage);
    if (!isOK)
        throw new BusinessException(errorMessage ?? "Some error occured.");
}

那么为什么我们得到编译错误?

6 个答案:

答案 0 :(得分:14)

当您将其传递给VerifySomeStuff时,您指定的是ref,但它还没有值。这是不合法的,因为VerifySomeStuff可以选择读取值,此时此值没有定义的值。分配null满足明确的分配要求。另一种选择是out

string errorMessage;
bool isOK = SomeClassWithBusinessRules.VerifySomeStuff(id, out errorMessage);
if (!isOK)
    throw new BusinessException(errorMessage ?? "Some error occured.");

这是合法的(但需要更改VerifySomeStuff,因为必须更改签名并且现在必需在退出之前为参数赋值(除非发生异常))。从显示的代码中,如果没有错误,您可以选择VerifySomeStuffnull分配给参数。

当然,如果bool和string然后重复“有问题”的目的,你也可以使用:

string errorMessage = SomeClassWithBusinessRules.VerifySomeStuff(id);
bool isOK = errorMessage == null;

答案 1 :(得分:13)

您收到编译错误,因为必须事先明确指定用作ref参数的变量。如果您更改方法以使用out参数,那就没问题了:

bool isOK = SomeClass.VerifySomeStuff(id, out errorMessage);

请注意,这也需要更改为VerifySomeStuff,以使其成为out参数。然后,该方法必须明确地在任何“正常”返回路径中分配一个值 - 这样,当方法正常返回时,errorMessage肯定被赋值。

分别参见第10.6.1.2节和第10.6.1.3节refout参数的详细信息。

答案 2 :(得分:6)

您正在通过errorMessage传递ref。这有进/出语义。换句话说,协议是接收者可以期望对象已经初始化,而你没有这样做。

好像你只想要out语义。更改VerifySomeStuff以使用out而不是ref errorMessage,并将调用代码更改为使用out

请注意,使用out传递时,在初始化对象之前,不允许被调用者读取。被调用者还有责任在返回之前执行该初始化。

答案 3 :(得分:5)

您还可以通过将方法更改为

来更正“错误”
 SomeClassWithBusinessRules.VerifySomeStuff(int idOfStuffToVerify, 
            out string  errorMessage);

当您使用out时,负担转移到方法,除非您对errorMessage参数进行赋值,否则它将无法编译。

答案 4 :(得分:2)

当传递ref参数时,被调用代码可以执行的操作之一是将ref参数变量重新指向新位置,即更新其引用。为了实现这一点,变量必须首先指向某个位置,因此必须对其进行分配,即使这仅仅是null

答案 5 :(得分:2)

你的问题(为什么编译器抱怨)已被其他人回答了。但是,我建议你重新考虑你的设计:

bool isOK = SomeClassWithBusinessRules.VerifySomeStuff(idOfStuffToVerify, ref errorMessage);
if (!isOK)
    throw new BusinessException(errorMessage ?? "Some error occured.");
}

由于只在发生错误时才需要errorMessage,为什么还需要额外的返回值?您可以将其缩短为:

string error = SomeClassWithBusinessRules.VerifySomeStuff(idOfStuffToVerify);
if (error != null)
    throw new BusinessException(error);
}

(当然,你不再有“发生了一些错误”的情况。但是显示“无用的”错误信息无论如何都是不好的做法。)

实际上,如果错误是特殊情况(即,某些事情不是常规控制流的一部分,而是指示数据或逻辑错误),那么移动它可能是有意义的异常里面 VerifySomeStuff:

// no return value
SomeClassWithBusinessRules.VerifySomeStuff(idOfStuffToVerify);

class SomeClassWithBusinessRules {
    void VerifySomeStuff(int id) {
        ...
        if (someCondition)
            throw new BusinessException(error);
        ...
    }
}