如何显式丢弃out参数?


99

我正在打电话:

myResult = MakeMyCall(inputParams, out messages);

但我实际上并不关心这些消息。如果它是输入参数,我不在乎,我只是传入一个null。如果那是回报,我不在乎,我就不理会它。

有没有办法用out做类似的事情,还是我需要声明一个我将忽略的变量?


类似的问题在这里:stackoverflow.com/questions/2870544/...
Dunc


谢谢!可惜它不是最新版本。
Andrew Ducker

Answers:


99

从C#7.0开始,可以避免预先声明参数并忽略它们。

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

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


1
不幸的是,C#7中不包括此功能(截至2017年4月)。
TIA

2
@tia。我已经更新了答案。显然,通配符从更改*_。抱歉,花了这么长时间。
Nolonar '17

14
他们应该坚持使用其out void语法的想法,而下划线似乎是一个奇怪的选择。
David Anderson

1
@ DavidAnderson-DCOM虽然我不喜欢下划线,但我认为他们需要用于重载解析的类型名称。
乔纳森·艾伦

看起来它仍在创建参数,因为我可以_ = {a value};在函数调用后添加行,而不会出现任何编译错误。
Bip901 '19

37

不幸的是,您需要传递某些内容,因为需要使用该方法来进行设置。因此您无法发送,null因为设置该方法所必需的方法会崩溃。

一种隐藏丑陋的方法是将方法包装在另一个out为您提供参数的方法中,如下所示:

String Other_MakeMyCall(String inputParams)
{
    String messages;

    return MakeMyCall(inputParams, out messages);
}

然后,您可以进行调用,Other_MakeMyCall而无需摆弄out不需要的参数。


37

您必须声明一个变量,然后将其忽略。在使用TryParse(或TryWhatever)模式来测试用户输入的有效性(例如,可以将其解析为数字吗?)而不关心实际的解析值时,最常见的情况就是这种情况。

您在问题中使用了“ dispose”一词,我怀疑这很不幸-但是,如果out参数是实现IDisposable的类型,则应该调用Dispose,除非方法文档中明确指出接收该值不所有权。我不记得曾经见过带有可抛弃out参数的方法,所以我希望这只是一个不幸的单词选择。


更多实用主义的反模式
Jodrell

11

如果原始函数是这样声明的:

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

您可以这样声明一个扩展方法:

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

扩展方法的行为类似于使out参数为可选的重载。


4

Visual Basic编译器通过创建虚拟变量来完成此任务。如果您可以说服Microsoft这是一个好主意,C#可以做到。


0

如果类的messages工具IDisposable,你不应该忽略它。考虑类似以下方法的方法(由于我有一段时间没有编写C#,因此在语法上可能不正确):

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

一旦离开using砖块,messages将被自动处置。


1
有趣。但是,您不必在using语句中初始化变量吗?
OregonGhost

1
@OregonGhost:是的,您知道。而且,如果您在using语句中更改变量的值,则仍然是原始值。
乔恩·斯基特

@JonSkeet无法理解它仍然是原始值。
Orkhan Alikhanov

@OrkhanAlikhanov:编译器基本上在using语句的开头获取变量的副本。因此,在块内更改该变量的值不会更改要处置的对象。
乔恩·斯基特

顺便说一句,应该有out messages
Orkhan Alikhanov

0

您必须为out参数传递一个变量。您不必在传递变量之前初始化变量:

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

通常,您可以在调用后忽略“消息”-除非出于某种原因(例如使用有限的系统资源)需要处理“消息”,在这种情况下,您应该调用Dispose():

messages.Dispose();

如果它可能使用大量内存,并且将在范围内保留一段时间,则如果它是引用类型,则可能应将其设置为null;如果是值类型,则应将其设置为新的默认实例,以便进行垃圾回收收集器可以回收内存:

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

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

0

在这种情况下,我为ConcurrentDictionary创建了一个通用的扩展方法,该方法没有Delete或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);
}

从ConcurrentDictionary实例调用时:

ClientList.TryRemoveIgnore(client.ClientId);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.