C#可选输出参数

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参数分配值,以及是否有任何方法可以避免这一点,即不指定值,而不显式地指定值null

例如,你必须写:

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;
}

有同样的结果吗?

简短的回答是不,这是不可避免的。请参阅文档中的示例,其中包括显式分配null,并说明:

Note that the third argument is assigned to null. This allows methods to return values optionally.

这方面的示例也可以在.NET框架中找到。例如:DictionaryTryGetValue方法:

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;
}

注意对default(TValue)的明确分配


使用不带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参数的重载。