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


当前回答

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

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# 4.0规范21.1节:

Formal parameters of constructors, methods, indexers and delegate types can be declared optional: fixed-parameter:     attributesopt parameter-modifieropt type identifier default-argumentopt default-argument:     = expression A fixed-parameter with a default-argument is an optional parameter, whereas a fixed-parameter without a default-argument is a required parameter. A required parameter cannot appear after an optional parameter in a formal-parameter-list. A ref or out parameter cannot have a default-argument.

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

实际上有一种方法可以做到这一点,这是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.

为了进行编译,您需要在项目选项中启用不安全代码。这是一个通常不应该使用的解决方案,但如果你为了一些奇怪的,神秘的,管理灵感的决定,确实需要一个可选的out参数在c#中,那么这将允许你这样做。

不,但你可以使用委托(例如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将在函数调用退出之前被调用。

它并不适合所有的用例,但是对于我的实际用例(一个为单元测试提供数据的函数,并且一个新的单元测试需要访问一些没有在返回值中出现的内部状态)来说效果很好。