c# 4.0允许可选的out或ref参数吗?


当前回答

像这样怎么样?

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

你仍然需要从c#中传递一个值给参数,但它是一个可选的ref参数。

其他回答

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
}

(感谢@奥斯卡/ @赖纳指出这一点。)

不是,但是另一个很好的替代方法是让方法使用一个泛型模板类来处理可选参数,如下所示:

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

这个直接的问题已经在其他得到好评的答案中得到了回答,但有时根据你想要实现的目标考虑其他方法是值得的。

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

ICYMI:包括在这里列举的c# 7.0的新特性中,“discards”现在被允许以_的形式作为out参数,让你忽略你不关心的out参数:

p.GetCoordinates(out var x, out _);//我只关心x

附注:如果你也对“输出变量x”的部分感到困惑,请阅读链接上关于“输出变量”的新功能。

对于简单类型,您可以使用不安全的代码来实现这一点,尽管这不是惯用的,也不是推荐的。像这样:

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