236

C# 4.0 是否允许可选outref参数?

4

10 回答 10

244

不。

一种解决方法是使用另一个没有out / ref 参数的方法重载,它只调用您当前的方法。

public bool SomeMethod(out string input)
{
    ...
}

// new overload
public bool SomeMethod()
{
    string temp;
    return SomeMethod(out temp);
}

如果你有C# 7.0,你可以简化:

// new overload
public bool SomeMethod()
{
    return SomeMethod(out _);    // declare out as an inline discard variable
}

(感谢@Oskar / @Reiner 指出这一点。)

于 2011-11-30T06:26:35.013 回答
98

如前所述,这根本是不允许的,我认为这很有意义。但是,为了添加更多细节,这里引用了C# 4.0 Specification的第 21.1 节:

构造函数、方法、索引器和委托类型的形式参数可以声明为可选的:

固定参数:
    属性选择参数修饰符选择类型标识符默认参数选择
默认参数:
    =表达式

  • 带有默认参数固定参数是可选参数,而没有默认参数的固定参数是必需参数
  • 必需参数不能出现在正式参数列表中的可选参数之后。
  • 一个reforout参数不能有一个default-argument
于 2010-05-20T02:06:58.923 回答
70

不,但另一个很好的选择是让方法使用通用模板类作为可选参数,如下所示:

public class OptionalOut<Type>
{
    public Type Result { get; set; }
}

然后你可以按如下方式使用它:

public string foo(string value, OptionalOut<int> outResult = null)
{
    // .. do something

    if (outResult != null) {
        outResult.Result = 100;
    }

    return value;
}

public void bar ()
{
    string str = "bar";

    string result;
    OptionalOut<int> optional = new OptionalOut<int> ();

    // example: call without the optional out parameter
    result = foo (str);
    Console.WriteLine ("Output was {0} with no optional value used", result);

    // example: call it with optional parameter
    result = foo (str, optional);
    Console.WriteLine ("Output was {0} with optional value of {1}", result, optional.Result);

    // example: call it with named optional parameter
    foo (str, outResult: optional);
    Console.WriteLine ("Output was {0} with optional value of {1}", result, optional.Result);
}
于 2014-02-24T15:06:06.577 回答
33

实际上有一种 C# 允许的方法。这又回到了 C++,而是违反了 C# 良好的面向对象结构。

谨慎使用此方法!

这是使用可选参数声明和编写函数的方式:

unsafe public void OptionalOutParameter(int* pOutParam = null)
{
    int lInteger = 5;
    // If the parameter is NULL, the caller doesn't care about this value.
    if (pOutParam != null) 
    { 
        // If it isn't null, the caller has provided the address of an integer.
        *pOutParam = lInteger; // Dereference the pointer and assign the return value.
    }
}

然后像这样调用函数:

unsafe { OptionalOutParameter(); } // does nothing
int MyInteger = 0;
unsafe { OptionalOutParameter(&MyInteger); } // pass in the address of MyInteger.

为了编译它,您需要在项目选项中启用不安全代码。这是一个通常不应该使用的非常 hacky 的解决方案,但是如果你为了一些奇怪的、神秘的、神秘的、受管理启发的决定,真的需要 C# 中的一个可选的 out 参数,那么这将允许你这样做。

于 2014-05-08T22:32:01.773 回答
7

ICYMI:包含在此处枚举的 C# 7.0 的新功能中,现在允许“丢弃”作为 _ 形式的输出参数,让您忽略不关心的参数:

p.GetCoordinates(out var x, out _); // I only care about x

PS,如果您也对“out var x”部分感到困惑,请阅读链接上有关“Out Variables”的新功能。

于 2017-03-10T08:08:24.160 回答
4

不,但您可以使用委托(例如Action)作为替代方案。

当面对我认为我想要一个可选的输出参数的情况时,部分受到 Robin R 的回答的启发,我改用了一个Action委托。我借用了他的示例代码来修改使用,Action<int>以显示差异和相似之处:

public string foo(string value, Action<int> outResult = null)
{
    // .. do something

    outResult?.Invoke(100);

    return value;
}

public void bar ()
{
    string str = "bar";

    string result;
    int optional = 0;

    // example: call without the optional out parameter
    result = foo (str);
    Console.WriteLine ("Output was {0} with no optional value used", result);

    // example: call it with optional parameter
    result = foo (str, x => optional = x);
    Console.WriteLine ("Output was {0} with optional value of {1}", result, optional);

    // example: call it with named optional parameter
    foo (str, outResult: x => optional = x);
    Console.WriteLine ("Output was {0} with optional value of {1}", result, optional);
}

这样做的好处是,可选变量在源代码中以普通 int 的形式出现(编译器将其包装在闭包类中,而不是我们将其显式包装在用户定义的类中)。

该变量需要显式初始化,因为编译器不能假定Action将在函数调用退出之前调用。

它并不适合所有用例,但适用于我的实际用例(为单元测试提供数据的函数,并且新的单元测试需要访问返回值中不存在的某些内部状态)。

于 2017-11-17T09:33:43.800 回答
0

对于简单类型,您可以使用不安全的代码来执行此操作,尽管这不是惯用的,也不推荐使用。像这样:

// unsafe since remainder can point anywhere
// and we can do arbitrary pointer manipulation
public unsafe int Divide( int x, int y, int* remainder = null ) {
    if( null != remainder ) *remainder = x % y;
    return x / y;
}

也就是说,没有理论上的理由 C# 最终不允许使用安全代码进行上述操作,如下所示:

// safe because remainder must point to a valid int or to nothing
// and we cannot do arbitrary pointer manipulation
public int Divide( int x, int y, out? int remainder = null ) {
    if( null != remainder ) *remainder = x % y;
    return x / y;
}

事情可能会变得有趣:

// remainder is an optional output parameter
// (to a nullable reference type)
public int Divide( int x, int y, out? object? remainder = null ) {
    if( null != remainder ) *remainder = 0 != y ? x % y : null;
    return x / y;
}
于 2021-12-08T21:43:18.393 回答
0

对于 C# 6.0 及更低版本,使用不带 out 参数的重载方法调用带 out 参数的方法。当专门询问 C# 4.0 是否可以具有可选的 out 参数时,我不确定为什么 .NET Core 的 C# 7.0 甚至是该线程的正确答案。答案是不!

于 2019-04-05T15:41:38.453 回答
-2

像这样呢?

public bool OptionalOutParamMethod([Optional] ref string pOutParam)
{
    return true;
}

您仍然需要从 C# 向参数传递一个值,但它是一个可选的 ref 参数。

于 2014-10-24T21:47:44.313 回答
-4
void foo(ref int? n)
{
    return null;
}
于 2016-06-15T13:47:26.793 回答