C# Optional Out Parameter
有没有办法使一个方法的out参数成为可选的?我有一个方法,在大多数情况下需要几个参数返回空值,但有时它们会有一个值。我试图找出是否有比先将值设置为空或在if/else之后将值设置为空更好的方法来完成此操作。这可能是唯一做到这一点的方法,但如果有可选的out参数或类似的东西,那就更好了。代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | private static void GetInitInfo(string initLine, string ncPointType, out double? relinquishDefault, out bool? ignoreRelinquishDefault, out bool? closedForStart, out bool? adjustDisabled) { relinquishDefault = null; ignoreRelinquishDefault = null; closedForStart = null; adjustDisabled = null; switch (ncPointType) { case"MSD": adjustDisabled = LastToken<bool?>(initLine); break; case"BO": relinquishDefault = SecondToken<double>(initLine); closedForStart = ThirdToken<bool?>(initLine); ignoreRelinquishDefault = !ForthToken<bool?>(initLine);//ignoreRelDef would be reverse of use initial value break; case"MSO": closedForStart = SecondToken<bool?>(initLine); relinquishDefault = ThirdToken<double>(initLine); ignoreRelinquishDefault = !ForthToken<bool?>(initLine);//ignoreRelDef would be reverse of use initial value break; case"AD": relinquishDefault = ThirdToken<double>(initLine); ignoreRelinquishDefault = false; break; case"BD": relinquishDefault = SecondToken<double>(initLine); adjustDisabled = LastToken<bool?>(initLine); ignoreRelinquishDefault = false; break; case"AOS": relinquishDefault = FirstToken<double>(initLine); ignoreRelinquishDefault = !ThirdToken<bool?>(initLine);//ignoreRelDef would be reverse of use initial value break; } } |
根据C 4.0规范第21.1节,这是不允许的。
解决方法是使用另一个没有out或ref参数的方法重载。
我认为这个问题是关于必须在方法内部使用out参数分配值,以及是否有任何方法可以避免这一点,即不指定值,而不显式地指定值
例如,你必须写:
1 2 3 4 5 | public bool OutMethod(out int? output) { output = null; return true; } |
或者有什么方法可以做到:
1 2 3 4 | public bool OutMethod(out int? output) { return true; } |
有同样的结果吗?
简短的回答是不,这是不可避免的。请参阅文档中的示例,其中包括显式分配
Note that the third argument is assigned to null. This allows methods to return values optionally.
这方面的示例也可以在.NET框架中找到。例如:
1 2 3 4 5 6 7 8 9 10 11 | public bool TryGetValue(TKey key, out TValue value) { int num = this.FindEntry(key); if (num >= 0) { value = this.entries[num].value; return true; } value = default(TValue); return false; } |
注意对
使用不带out参数的签名的重载:
1 2 3 4 5 6 7 8 9 10 | private static void GetInitInfo(string initLine, string ncPointType) { double? relinquishDefault; bool? ignoreRelinquishDefault; bool? closedForStart; bool? adjustDisabled; GetInitInfo( initLine, ncPointType, out relinquishDefault, out ignoreRelinquishDefault, out closedForStart, out adjustDisabled); } |
解释很简单:你可以做到。只需在方法内部为所需值分配一个out参数。
现在你可以问自己,为什么我们不能在方法签名中这样做?好吧,让我们来看看正常的可选值参数。如果调用者没有指定,则会为它们分配一个预定义的值。所以调用者知道这个值,如果参数没有显式设置,它将被传递。它拥有对它的控制权,并对这个决定负责。
由于方法的调用方不负责分配out参数,因此提供默认值是没有意义的。通过使用默认的out参数值,您唯一可以实现的就是让调用者知道该out参数的可能值之一是什么。但这有道理吗?这个值什么时候使用?在什么情况下?所有这些仍然对呼叫方隐藏。因此,拥有一个可选的out参数值并没有真正的好处,除了可以在签名中而不是方法体中设置它之外。
因此,这么说,以下内容没有多大意义:
1 | public bool TrySomething(out string outObject ="default value") { ... } |
然而,最酷的是允许以下方法
1 | public bool TrySomething(out string outObject) { ... } |
调用如下:
1 | bool result = TrySomething(); |
并且在幕后相当于:
1 2 | string dummyWhichWillNeverBeUsed; bool succeeded = TrySomething(out dummyWhichWillNeverBeUsed); |
不幸的是,这是不允许的。
当然,正如其他答案中所解释的那样,您总是可以有没有out参数的重载。