c# 4.0允许可选的out或ref参数吗?
当前回答
对于c# 6.0及以下版本,使用不带out形参的重载方法调用带out形参的方法。当被特别问到c# 4.0是否可以有一个可选的out参数时,我不确定为什么用于。net Core的c# 7.0甚至是这个线程的正确答案。答案是否定的!
其他回答
ICYMI:包括在这里列举的c# 7.0的新特性中,“discards”现在被允许以_的形式作为out参数,让你忽略你不关心的out参数:
p.GetCoordinates(out var x, out _);//我只关心x
附注:如果你也对“输出变量x”的部分感到困惑,请阅读链接上关于“输出变量”的新功能。
不,但你可以使用委托(例如Action)作为替代。
当我想要一个可选的out参数时,部分受到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将在函数调用退出之前被调用。
它并不适合所有的用例,但是对于我的实际用例(一个为单元测试提供数据的函数,并且一个新的单元测试需要访问一些没有在返回值中出现的内部状态)来说效果很好。
No.
一个解决方法是重载另一个没有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
}
(感谢@奥斯卡/ @赖纳指出这一点。)
这个直接的问题已经在其他得到好评的答案中得到了回答,但有时根据你想要实现的目标考虑其他方法是值得的。
If you're wanting an optional parameter to allow the caller to possibly request extra data from your method on which to base some decision, an alternative design is to move that decision logic into your method and allow the caller to optionally pass a value for that decision criteria in. For example, here is a method which determines the compass point of a vector, in which we might want to pass back the magnitude of the vector so that the caller can potentially decide if some minimum threshold should be reached before the compass-point judgement is far enough away from the origin and therefore unequivocally valid:
public enum Quadrant {
North,
East,
South,
West
}
// INVALID CODE WITH MADE-UP USAGE PATTERN OF "OPTIONAL" OUT PARAMETER
public Quadrant GetJoystickQuadrant([optional] out magnitude)
{
Vector2 pos = GetJoystickPositionXY();
float azimuth = Mathf.Atan2(pos.y, pos.x) * 180.0f / Mathf.PI;
Quadrant q;
if (azimuth > -45.0f && azimuth <= 45.0f) q = Quadrant.East;
else if (azimuth > 45.0f && azimuth <= 135.0f) q = Quadrant.North;
else if (azimuth > -135.0f && azimuth <= -45.0f) q = Quadrant.South;
else q = Quadrant.West;
if ([optonal.isPresent(magnitude)]) magnitude = pos.Length();
return q;
}
在这种情况下,我们可以将“最小大小”逻辑移动到方法中,并以一个更清晰的实现结束,特别是因为计算大小涉及到一个平方根,所以如果我们只想做大小的比较,那么计算效率就会很低,因为我们可以用平方值来比较:
public enum Quadrant {
None, // Too close to origin to judge.
North,
East,
South,
West
}
public Quadrant GetJoystickQuadrant(float minimumMagnitude = 0.33f)
{
Vector2 pos = GetJoystickPosition();
if (minimumMagnitude > 0.0f && pos.LengthSquared() < minimumMagnitude * minimumMagnitude)
{
return Quadrant.None;
}
float azimuth = Mathf.Atan2(pos.y, pos.x) * 180.0f / Mathf.PI;
if (azimuth > -45.0f && azimuth <= 45.0f) return Quadrant.East;
else if (azimuth > 45.0f && azimuth <= 135.0f) return Quadrant.North;
else if (azimuth > -135.0f && azimuth <= -45.0f) return Quadrant.South;
return Quadrant.West;
}
当然,这可能并不总是可行的。由于其他答案提到了c# 7.0,如果你真正要做的是返回两个值,并允许调用者可选地忽略其中一个,那么惯用的c#将返回两个值的元组,并使用c# 7.0的元组与位置初始化器和_ "discard"参数:
public (Quadrant, float) GetJoystickQuadrantAndMagnitude()
{
Vector2 pos = GetJoystickPositionXY();
float azimuth = Mathf.Atan2(pos.y, pos.x) * 180.0f / Mathf.PI;
Quadrant q;
if (azimuth > -45.0f && azimuth <= 45.0f) q = Quadrant.East;
else if (azimuth > 45.0f && azimuth <= 135.0f) q = Quadrant.North;
else if (azimuth > -135.0f && azimuth <= -45.0f) q = Quadrant.South;
else q = Quadrant.West;
return (q, pos.Length());
}
(Quadrant q, _) = GetJoystickQuadrantAndMagnitude();
if (q == Quadrant.South)
{
// Do something.
}
对于简单类型,您可以使用不安全的代码来实现这一点,尽管这不是惯用的,也不是推荐的。像这样:
// 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# 4.0可选的out/ref参数
- c# 4.0中的“动态”类型是用来干什么的?
- 平行的。ForEach vs Task.Factory.StartNew
- 动态地向ExpandoObject添加属性
- x = x || y是什么意思?
- 在Tuple类中比"Item1", "Item2"更好的命名
- 普通参数与关键字参数
- .NET NewtonSoft JSON反序列化映射到不同的属性名
- 可选关键字参数的命名元组和默认值
- 如何定义具有可选参数的函数?
- 是否有一种方法在JavaScript函数调用中提供命名参数?
- 为什么在接口上定义的c# 4可选参数没有强制实现类?
- 如何在Swift协议中声明可选方法?
- 任务和线程的区别是什么?
- 如何在c#中使用可选参数?