C# 4.0 необязательные аргументы out/ref

позволяет ли C# 4.0 необязательный out или ref аргументы?

8 ответов


Как уже упоминалось, это просто не разрешено, и я думаю, что это имеет очень хороший смысл. Однако, чтобы добавить некоторые дополнительные детали, вот цитата из Спецификация C# 4.0 раздел 21.1:

формальные параметры конструкторов, методов, индексаторов и типов делегатов могут быть объявлены необязательными:

фиксированный параметр:
    атрибутыopt


нет.

обходным путем является перегрузка другим методом, который не имеют параметры 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 за указание на это.)


нет, но другой отличной альтернативой является то, что метод использует общий класс шаблона для дополнительных параметров следующим образом:

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#, то это позволит вам сделать именно это.


ICYMI: включено в новые функции для C# 7.0 перечислено здесь, "отбрасывает" теперь разрешено в качестве параметров в виде_, чтобы вы могли игнорировать параметры, которые вам не нужны:

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

P.S. Если вы также путаете с частью "out var x", прочитайте новую функцию о" Out Variables " по ссылке.


нет, но вы можете использовать делегат (например,Action) в качестве альтернативы.

вдохновленный частично ответом Робина R при столкновении с ситуацией, когда я думал, что хочу необязательный параметр out, я вместо этого использовал 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 (компилятор обертывает ее в closure class, а не мы явно оборачиваем его в пользовательский класс).

переменная нуждается в явной инициализации, потому что компилятор не может предположить, что Action будет вызываться до завершения вызова функции.

это не подходит для всех случаев использования, но хорошо работает для моего реального случая использования (функция, которая предоставляет данные для модульного теста, и где новый модульный тест необходим доступ к некоторому внутреннему состоянию, отсутствующему в возвращаемом значении).


Как насчет такой?

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

вам все равно нужно передать значение параметру из C#, но это необязательный параметр ref.


void foo(ref int? n)
{
    return null;
}