代码之家  ›  专栏  ›  技术社区  ›  Joe Daley

C 4.0可选的out/ref参数

  •  188
  • Joe Daley  · 技术社区  · 15 年前

    C 4.0是否允许可选 out ref 争论?

    8 回复  |  直到 7 年前
        1
  •  85
  •   Tomas Petricek    15 年前

    如前所述,这是不允许的,我认为这是非常合理的。 但是,要添加更多详细信息,这里是来自 C# 4.0 Specification 第21.1节:

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

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

    • 固定参数 用一个 默认参数 是一个 可选参数 而A 固定参数 没有 默认参数 是一个 必需参数 .
    • 形式参数表 .
    • ref out 参数不能有 默认参数 .
        2
  •  171
  •   Dunc    7 年前

    不。

    解决方法是使用另一种方法 有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指出这一点。)

        3
  •  61
  •   Robin R    11 年前

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

    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);
    }
    
        4
  •  26
  •   neonblitzer MakePeaceGreatAgain    10 年前

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

    要编译此代码,需要在项目选项中启用不安全代码。这是一个通常不应该使用的非常简单的解决方案,但是如果您需要一些奇怪的、神秘的、管理层启发的决策,在C中确实需要一个可选的out参数,那么这将允许您这样做。

        5
  •  5
  •   jbdeguzman    8 年前

    Icemi:包含在C 7.0的新功能中枚举 here 现在允许将“discards”作为a_u形式的out参数,让您忽略不关心的out参数:

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

    另外,如果您还对“out var x”这一部分感到困惑,请阅读链接上关于“out variables”的新功能。

        6
  •  1
  •   Steve    7 年前

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

    在某种程度上受到Robin R回答的启发,当我面对一个我认为需要可选out参数的情况时,我使用了 行动 代表。我借用了他的示例代码来修改 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出现在源代码中(编译器将其包装在一个闭包类中,而不是显式包装在用户定义的类中)。

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

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

        7
  •  -2
  •   Aaron L.    10 年前

    像这样怎么样?

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

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

        8
  •  -4
  •   user6469927    9 年前
    void foo(ref int? n)
    {
        return null;
    }