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 перечислено здесь, "отбрасывает" теперь разрешено в качестве параметров out в виде_, чтобы вы могли игнорировать параметры, которые вас не волнуют:
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 (компилятор обертывает его в a класс закрытия, а не мы явно обертываем его в пользовательский класс).
переменная нуждается в явной инициализации, поскольку компилятор не может предположить, что
Action
будет вызван до завершения вызова функции.это не подходит для всех случаев использования, но хорошо работает для моего реального случая использования (функция, которая предоставляет данные для модульного теста, и где новый модульный тест необходим доступ к некоторому внутреннему состоянию, не присутствующему в возвращаемом значении).