C # 4.0 необязательные аргументы out / ref - PullRequest
193 голосов
/ 20 мая 2010

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

Ответы [ 9 ]

180 голосов
/ 30 ноября 2011

номер

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

87 голосов
/ 20 мая 2010

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

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

фиксированный параметр:
атрибуты опт модификатор параметра опт идентификатор типа аргумент по умолчанию опт
default-аргумент:
= выражение

  • A фиксированный параметр с аргументом по умолчанию является необязательным параметром , тогда как фиксированный параметр без аргумент по умолчанию является обязательным параметром .
  • Обязательный параметр не может появиться после необязательного параметра в формальном-списке параметров .
  • Параметр ref или out не может иметь аргумент по умолчанию .
63 голосов
/ 24 февраля 2014

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

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);
}
26 голосов
/ 09 мая 2014

На самом деле есть способ сделать это, что разрешено в 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 #, тогда это позволит вам сделать именно это. 1011 *

5 голосов
/ 10 марта 2017

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

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

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

1 голос
/ 17 ноября 2017

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

Вдохновленный ответом Робина Р., когда я столкнулся с ситуацией, когда я думал, что хочу дополнительный параметр 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);
}

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

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

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

0 голосов
/ 05 апреля 2019

Используйте перегруженный метод без параметра out, чтобы вызвать метод с параметром out для C # 6.0 и ниже. Я не уверен, почему C # 7.0 для .NET Core даже является правильным ответом для этой темы, когда его специально спросили, может ли C # 4.0 иметь необязательный параметр out. Ответ НЕТ!

0 голосов
/ 15 июня 2016
void foo(ref int? n)
{
    return null;
}
0 голосов
/ 25 октября 2014

Как насчет этого?

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

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

...