C# 4.0 是否允许可选out
或ref
参数?
10 回答
不。
一种解决方法是使用另一个没有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 指出这一点。)
如前所述,这根本是不允许的,我认为这很有意义。但是,为了添加更多细节,这里引用了C# 4.0 Specification的第 21.1 节:
构造函数、方法、索引器和委托类型的形式参数可以声明为可选的:
固定参数:
属性选择参数修饰符选择类型标识符默认参数选择
默认参数:
=表达式
- 带有默认参数的固定参数是可选参数,而没有默认参数的固定参数是必需参数。
- 必需参数不能出现在正式参数列表中的可选参数之后。
- 一个
ref
orout
参数不能有一个default-argument。
不,但另一个很好的选择是让方法使用通用模板类作为可选参数,如下所示:
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);
}
实际上有一种 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 参数,那么这将允许你这样做。
ICYMI:包含在此处枚举的 C# 7.0 的新功能中,现在允许“丢弃”作为 _ 形式的输出参数,让您忽略不关心的参数:
p.GetCoordinates(out var x, out _); // I only care about x
PS,如果您也对“out var x”部分感到困惑,请阅读链接上有关“Out Variables”的新功能。
不,但您可以使用委托(例如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
将在函数调用退出之前调用。
它并不适合所有用例,但适用于我的实际用例(为单元测试提供数据的函数,并且新的单元测试需要访问返回值中不存在的某些内部状态)。
对于简单类型,您可以使用不安全的代码来执行此操作,尽管这不是惯用的,也不推荐使用。像这样:
// 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;
}
对于 C# 6.0 及更低版本,使用不带 out 参数的重载方法调用带 out 参数的方法。当专门询问 C# 4.0 是否可以具有可选的 out 参数时,我不确定为什么 .NET Core 的 C# 7.0 甚至是该线程的正确答案。答案是不!
像这样呢?
public bool OptionalOutParamMethod([Optional] ref string pOutParam)
{
return true;
}
您仍然需要从 C# 向参数传递一个值,但它是一个可选的 ref 参数。
void foo(ref int? n)
{
return null;
}