out引数を明示的に破棄する方法は?


99

私は電話をかけています:

myResult = MakeMyCall(inputParams, out messages);

しかし、私は実際にはメッセージについて気にしません。それが入力パラメーターである場合、私は気にせず、nullを渡します。返品の場合は気にせず、そのままにしておきます。

outで同様のことを行う方法はありますか、それとも無視する変数を宣言する必要がありますか?


ここでは、同様の質問:stackoverflow.com/questions/2870544/...
Dunc


ありがとう!残念ですが、最新バージョンではありません。
Andrew Ducker

回答:


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 2017

14
out void構文に使用するという考えにこだわっている必要があり、アンダースコアは奇妙な選択のようです。
デビッドアンダーソン

1
@ DavidAnderson-DCOM私はアンダースコアのファンではありませんが、オーバーロードを解決するには型名が必要だと思います。
ジョナサンアレン

_ = {a value};コンパイルエラーなしで関数呼び出しの後に行を追加できるので、まだパラメーターを作成しているようです。
Bip901

37

残念ながら、メソッドはそれを設定する必要があるため、何かを渡す必要があります。だからあなたは送ることができませんnullため、設定する必要があるメソッドが爆発するため、。

醜さを隠す1つの方法は、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 2016年

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

のクラスがmessagesimplements IDisposableである場合は、無視しないでください。次のようなアプローチを考えてみてください(しばらくの間C#を記述していないため、構文的に正しくない可能性があります)。

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

usingブロックの外側にmessagesなると、自動的に処分されます。


1
面白い。しかし、usingステートメントで変数を初期化する必要はありませんか?
OregonGhost 2009年

1
@OregonGhost:はい、そうです。そして、usingステートメント内で変数の値を変更しても、破棄されるのは元の値のままです。
Jon Skeet、

@JonSkeet 廃棄されたのは元の値のままだと
Orkhan Alikhanov 2016

@OrkhanAlikhanov:コンパイラーは基本的に、usingステートメントの開始時に変数のコピーを取得します。したがって、ブロック内でその変数の値を変更しても、破棄されるオブジェクトは変わりません。
ジョンスキート

ちなみに、あるはずですout messages
オルカンアリカノフ2016

0

outパラメータには変数を渡す必要があります。渡す前に変数を初期化する必要はありません:

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

通常、呼び出し後の 'messages'は無視できます-限られたシステムリソースの使用など、何らかの理由で '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);
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.