¿Cómo descartar explícitamente un argumento de salida?


99

Estoy haciendo una llamada:

myResult = MakeMyCall(inputParams, out messages);

pero en realidad no me preocupan los mensajes. Si fuera un parámetro de entrada que no me importara, simplemente pasaría un valor nulo. Si era el regreso que no me importaba, simplemente lo dejaría fuera.

¿Hay alguna manera de hacer algo similar sin una salida, o necesito declarar una variable que luego ignoraré?




¡Gracias! Es una pena que no esté en la última versión.
Andrew Ducker

Respuestas:


99

A partir de C # 7.0, es posible evitar la clarificación previa de los parámetros y también ignorarlos.

public void PrintCoordinates(Point p)
{
    p.GetCoordinates(out int x, out int y);
    WriteLine($"({x}, {y})");
}

public void PrintXCoordinate(Point p)
{
    p.GetCoordinates(out int x, out _); // I only care about x
    WriteLine($"{x}");
}

Fuente: https://blogs.msdn.microsoft.com/dotnet/2017/03/09/new-features-in-c-7-0/


1
Desafortunadamente, esto no está incluido en C # 7 (a partir de abril de 2017).
tia

2
@tia. Actualicé mi respuesta. Aparentemente, el carácter comodín se cambió de *a _. Lamento que haya tardado tanto.
Nolonar

14
Deberían haberse quedado con su idea de usar out voidla sintaxis, y el subrayado parece una elección extraña.
David Anderson

1
@ DavidAnderson-DCOM Si bien no soy fanático del subrayado, creo que necesitan el nombre del tipo para la resolución de sobrecarga.
Jonathan Allen

Parece que todavía crea un parámetro, porque puedo agregar la línea _ = {a value};después de la llamada a la función sin errores de compilación.
Bip901

37

Desafortunadamente, debe pasar algo porque se requiere el método para configurarlo. Por lo tanto, no puede enviar nullporque el método, al ser requerido para configurarlo, explotaría.

Un enfoque para ocultar la fealdad sería envolver el método en otro método que haga el outparámetro por usted así:

String Other_MakeMyCall(String inputParams)
{
    String messages;

    return MakeMyCall(inputParams, out messages);
}

Entonces puede llamar Other_MakeMyCallsin tener que jugar con outparámetros que no necesita.


37

Tienes que declarar una variable que luego ignorarás. Este es el caso más común con el patrón TryParse (o TryWhatever), cuando se usa para probar la validez de la entrada del usuario (por ejemplo, ¿se puede analizar como un número?) Sin preocuparse por el valor analizado real.

Usó la palabra "dispose" en la pregunta, lo cual sospecho que fue simplemente desafortunado, pero si el parámetro out es de un tipo que implementa IDisposable, ciertamente debe llamar a Dispose a menos que la documentación del método indique explícitamente que recibir el valor no confiere propiedad. Sin outembargo, no recuerdo haber visto nunca un método con un parámetro desechable , así que espero que haya sido una mala elección de palabras.


Más de un anti-patrón pragmático
Jodrell

11

Si la función original se declara así:

class C
{
    public Result MakeMyCall(Object arg, out List<String> messages);
}

Puede declarar un método de extensión como este:

static class CExtension
{
    public static Result MakeMyCall(this C obj, Object arg)
    {
        List<String> unused;
        return obj.MakeMyCall(arg, out unused);
    }
}

El método de extensión se comportará como una sobrecarga que hace que el parámetro out sea opcional.


4

El compilador de Visual Basic hace esto creando una variable ficticia. C # podría hacerlo, si puedes convencer a Microsoft de que es una buena idea.


0

Si la clase de messagesimplementos IDisposable, no debe ignorarla. Considere algo como el siguiente enfoque (puede que no sea sintácticamente correcto ya que no he escrito C # en un tiempo):

using (FooClass messages) {
    myResult = MakeMyCall(inputParams, messages);
}

Una vez fuera del usingbloque, messagesse eliminará automáticamente.


1
Interesante. ¿Pero no tienes que inicializar la variable en la instrucción using?
OregonGhost

1
@OregonGhost: Sí, lo haces. Y si cambia el valor de la variable dentro de la declaración using, sigue siendo el valor original el que se elimina.
Jon Skeet

@JonSkeet No se pudo comprender , sigue siendo el valor original que se elimina.
Orkhan Alikhanov

@OrkhanAlikhanov: El compilador básicamente toma una copia de la variable al comienzo de la usingdeclaración. Entonces, cambiar el valor de esa variable dentro del bloque no cambia qué objeto se elimina.
Jon Skeet

Por cierto, debería haberlo out messages.
Orkhan Alikhanov

0

Debe pasar una variable para el parámetro out. No es necesario que inicialice la variable antes de pasarla:

MyMessagesType messages;
myResult = MakeMyCall(inputParams, out messages); 

Por lo general, puede simplemente ignorar los 'mensajes' después de la llamada, a menos que los 'mensajes' necesiten eliminarse por algún motivo, como el uso de recursos limitados del sistema, en cuyo caso debe llamar a Dispose ():

messages.Dispose();

Si puede usar una cantidad significativa de memoria y permanecerá dentro del alcance por un tiempo, probablemente debería establecerse en nulo si es un tipo de referencia o en una nueva instancia predeterminada si es un tipo de valor, de modo que la basura colector puede reclamar la memoria:

messages = null; // Allow GC to reclaim memory for reference type.

messages = new MyMessageType(); // Allow GC to reclaim memory for value type.

0

En este caso, hice un método de extensión genérico para ConcurrentDictionary que no tiene ningún método Delete o Remove.

//Remove item from list and ignore reference to removed item
public static void TryRemoveIgnore<K,T>(this ConcurrentDictionary<K,T> dictionary, K key)
{
    T CompletelyIgnored;
    dictionary.TryRemove(key, out CompletelyIgnored);
}

Cuando se llama desde una instancia de ConcurrentDictionary:

ClientList.TryRemoveIgnore(client.ClientId);
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.