How to explicitly discard an out argument?
Asked Answered
R

8

127

I'm making a call:

myResult = MakeMyCall(inputParams, out messages);

but I don't actually care about the messages. If it was an input parameter I didn't care about I'd just pass in a null. If it was the return I didn't care about I'd just leave it off.

Is there a way to do something similar with an out, or do I need to declare a variable that I will then ignore?

Rutabaga answered 20/1, 2009 at 17:6 Comment(3)
Similar question here: #2871044Err
related: #31724663Sycophancy
Thanks! Shame it's not in the latest version.Rutabaga
T
148

Starting with C# 7.0, it is possible to avoid predeclaring out parameters as well as ignoring them.

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}");
}

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

Truce answered 30/11, 2016 at 13:49 Comment(7)
Unfortunately, this is not included in C# 7 (as of Apr 2017).Bausch
@tia. I've updated my answer. Apparently, the wildcard character was changed from * to _. Sorry it took so long.Truce
They should have stuck with their idea to use out void for the syntax, and underscore seems like an odd choice.Harbot
@DavidAnderson-DCOM While I'm no fan of underscore, I think they need the type name for overload resolution.Illaudable
It looks like it still creates a parameter, because I can add the line _ = {a value}; after the function call without any compilation errors.Insipience
I think passing out null as an argument would look better, by the way in case someone wants to omit it, it would be good to have something like default parameters so setting out objectType = null in the parameter it should ignore its argument then you could omit it as well.Files
This doesn't work for me. error: The name '_' does not exist in the current context. It is a regular asp.net mvc application. Do I need to do anything else?Blennioid
Q
38

You have to declare a variable which you will then ignore. This is most commonly the case with the TryParse (or TryWhatever) pattern, when it is used to test the validity of user input (e.g. can it be parsed as a number?) without caring about the actual parsed value.

You used the word "dispose" in the question, which I suspect was just unfortunate - but if the out parameter is of a type which implements IDisposable, you should certainly call Dispose unless the method documentation explicitly states that receiving the value doesn't confer ownership. I can't remember ever seeing a method with a disposable out parameter though, so I'm hoping this was just an unlucky choice of words.

Quarrier answered 20/1, 2009 at 17:20 Comment(1)
More of a pragmatic anti-patternHumus
S
37

Unfortunately you are required to pass something because the method is required to set it. So you cannot send null because the method, being required to set it, would blow up.

One approach to hide the ugliness would be to wrap the method in another method that does the out parameter for you like so:

String Other_MakeMyCall(String inputParams)
{
    String messages;

    return MakeMyCall(inputParams, out messages);
}

Then you can call Other_MakeMyCall without having to fiddle with out parameters you don't need.

Scion answered 20/1, 2009 at 17:9 Comment(0)
N
11

If the original function is declared like this:

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

You can declare an extension method like this:

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

The extension method will behave like an overload that makes the out parameter optional.

Novelia answered 20/1, 2009 at 18:59 Comment(0)
I
4

The Visual Basic compiler does this by creating a dummy variable. C# could do it, if you can convince Microsoft its a good idea.

Illaudable answered 20/1, 2009 at 17:28 Comment(0)
E
0

If the class of messages implements IDisposable, you shouldn't ignore it. Consider something like the following approach (may not be syntactically correct since I haven't written C# in a while):

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

Once outside the using block, messages will be disposed automatically.

Exceeding answered 20/1, 2009 at 17:12 Comment(5)
Interesting. But don't you have to initialize the variable in the using statement?Lotson
@OregonGhost: Yes, you do. And if you change the value of the variable within the using statement, it's still the original value which is disposed.Quarrier
@JonSkeet Couldn't grasp it's still the original value which is disposed.Belfry
@OrkhanAlikhanov: The compiler basically takes a copy of the variable at the start of the using statement. So changing the value of that variable within the block doesn't change which object gets disposed.Quarrier
By the way, there should be out messages.Belfry
T
0

You must pass a variable for the out parameter. You do not have to initialize the variable before passing it:

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

Typically, you can just ignore 'messages' after the call - unless 'messages' needs disposing for some reason, such as the use of limited system resources, in which case you should call Dispose():

messages.Dispose();

If it might use a significant amount of memory and it is going to remain in scope for a while, it should probably be set to null if it is a reference type or to a new default instance if it's a value type, so that the garbage collector can reclaim the memory:

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

messages = new MyMessageType(); // Allow GC to reclaim memory for value type.
Teirtza answered 20/1, 2009 at 17:28 Comment(0)
L
0

In this case I made an generic extension method for ConcurrentDictionary that has no Delete or Remove method.

//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);
}

When called from an instance of ConcurrentDictionary:

ClientList.TryRemoveIgnore(client.ClientId);
Luxor answered 3/11, 2017 at 12:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.