c#-4.0 - pasaje - parametros opcionales c#
C#4.0 opcional argumentos de salida/ref (8)
¿C # 4.0 permite argumentos opcionales de out
o ref
?
¿Qué tal como esto?
public bool OptionalOutParamMethod([Optional] ref string pOutParam)
{
return true;
}
Aún debe pasar un valor al parámetro desde C #, pero es un parámetro de referencia opcional.
Como ya se mencionó, esto simplemente no está permitido y creo que tiene un muy buen sentido. Sin embargo, para agregar algunos más detalles, aquí hay una cita de la Especificación C # 4.0 , sección 21.1:
Los parámetros formales de constructores, métodos, indizadores y tipos de delegado se pueden declarar opcionales:
parámetro fijo:
atributos opt parámetro-modificador opt tipo identificador default-argumento opt
argumento por defecto:
= expresión
- Un parámetro fijo con un argumento predeterminado es un parámetro opcional , mientras que un parámetro fijo sin un argumento predeterminado es un parámetro requerido .
- Un parámetro requerido no puede aparecer después de un parámetro opcional en una lista formal de parámetros .
- Un parámetro
ref
oout
no puede tener un argumento predeterminado .
De hecho, hay una forma de hacer esto que C # permite. Esto vuelve a C ++, y más bien viola la agradable estructura orientada a objetos de C #.
¡USE ESTE MÉTODO CON PRECAUCIÓN!
Así es como declaras y escribes tu función con un parámetro opcional:
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.
}
}
Luego llame a la función de esta manera:
unsafe { OptionalOutParameter(); } // does nothing
int MyInteger = 0;
unsafe { OptionalOutParameter(&MyInteger); } // pass in the address of MyInteger.
Para poder compilar esto, deberá habilitar el código no seguro en las opciones del proyecto. Esta es una solución realmente hacky que por lo general no debería usarse, pero si para una decisión extraña, misteriosa, misteriosa e inspirada en la administración, REALMENTE necesita un parámetro out opcional en C #, entonces esto le permitirá hacer precisamente eso.
ICYMI: Incluido en las nuevas características para C # 7.0 enumeradas here , "descartes" ahora está permitido como parámetros de salida en forma de _, para permitirle ignorar los parámetros que no le interesan:
p.GetCoordinates(out var x, out _); // I only care about x
PD: si también está confundido con la parte "out var x", lea también la nueva función sobre "Out Variables" en el enlace.
No, pero otra gran alternativa es hacer que el método use una clase de plantilla genérica para parámetros opcionales de la siguiente manera:
public class OptionalOut<Type>
{
public Type Result { get; set; }
}
Entonces puedes usarlo de la siguiente manera:
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);
}
No, pero puede usar un delegado (por ejemplo, Action
) como alternativa.
Inspirado en parte por la respuesta de Robin R cuando enfrentaba una situación en la que pensaba que quería un parámetro de salida opcional, en su lugar usé un delegado de Action
. He tomado prestado su código de ejemplo para modificar el uso de Action<int>
para mostrar las diferencias y similitudes:
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);
}
Esto tiene la ventaja de que la variable opcional aparece en la fuente como un int normal (el compilador lo envuelve en una clase de cierre, en lugar de que nosotros lo envolvemos explícitamente en una clase definida por el usuario).
La variable necesita una inicialización explícita porque el compilador no puede suponer que se invocará la Action
antes de que la llamada a la función finalice.
No es adecuado para todos los casos de uso, pero funcionó bien para mi caso de uso real (una función que proporciona datos para una prueba de unidad, y donde una nueva prueba de unidad necesitaba acceso a algún estado interno no presente en el valor de retorno).
No.
Una solución alternativa es sobrecargar con otro método que no tenga parámetros out / ref y que solo llame a su método actual.
public bool SomeMethod(out string input)
{
...
}
// new overload
public bool SomeMethod()
{
string temp;
return SomeMethod(out temp);
}
Actualización: si tiene C # 7.0 , puede simplificar:
// new overload
public bool SomeMethod()
{
return SomeMethod(out _); // declare out as an inline discard variable
}
(Gracias @Oskar / @Reiner por señalar esto).
void foo(ref int? n)
{
return null;
}