这是我一段时间以来一直想知道的事情。我在标题中浏览了一系列包含错误的问题,但找不到解释此案例的问题。
首先看一下这个例子:
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.");
}
那么为什么我们得到编译错误?
答案 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
,因为必须更改签名并且现在必需在退出之前为参数赋值(除非发生异常))。从显示的代码中,如果没有错误,您可以选择VerifySomeStuff
将null
分配给参数。
当然,如果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节ref
和out
参数的详细信息。
答案 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);
...
}
}