C#4.0オプションのout / ref引数


212

C#4.0はオプションoutまたはref引数を許可しますか?


2
よく、C ++は「out」パラメーターに対してそれらを効果的に持っています-アドレス引数をnullに初期化することができ、ポインターがnullでない場合にのみそのような戻り構造にデータを追加するライブラリコードを書くことは非常に一般的です。これは、C APIの「オプションの引数」にnullを使用することに戻る慣用句です。
アンディ・デント、

53
@エドとみんな:なぜこれが意味をなさないのですか?関数が「out」を介して値を「返す」場合、それを強制的に受け入れられたくありません。技術的な理由から、コンパイラはまだ何かを渡さなければならないことを知っていますが、背後でダミーのローカルを作成できなかった理由はありません。
Roman Starkov

5
実装方法やオプションのパラメーターが実際に何であるかという観点からは、意味がないかもしれません。しかし、romkynsが言ったように、「オプションのout引数」があると本当に良いでしょう。CLRではなく英語でそれを解析すれば、合理的かつIMOで望ましいものになります。
Adam Tolley、2010

9
C#ではサポートされていませんが、VB.NETではサポートされています。
Jason

5
これは打ちのめされてしまいましたが、オプションのout引数のサポートについて言及せざるを得ません。nullデフォルトの設定(私はPHPから来ています介してオプションの引数にかなり慣れ、引数の入力nullを続行するためのテストを(慣れ親しんだ人のためにpreg_match())とにかく、とにかく、技術的な点から理解すると、これは現在のところ不可能であり、そのPHPとC#はかなり比類のないものですが、それでも利用可能素晴らしい」ツールです。
Dan Lugg、2012

回答:


93

すでに述べたように、これは単に許可されておらず、非常に理にかなっていると思います。ただし、さらに詳細を追加するために、C#4.0仕様のセクション21.1 からの引用を次に示します。

コンストラクター、メソッド、インデクサー、デリゲート型の仮パラメーターはオプションとして宣言できます。

fixed-parameter:
    attributes opt parameter-modifier opt type identifier default-argument opt
default-argument:
    = expression

  • 固定パラメータデフォルト引数であるオプションのパラメータに対し、固定パラメータなしのデフォルト引数がある必須パラメータ
  • 必須パラメーターは、formal-parameter-listのオプションパラメーターの後に表示することはできません。
  • A refまたはoutパラメータが持つことができませんデフォルト引数を

または、ref / outパラメーターを使用してオーバーロードを作成できます。はい、関数の定義は2つありますが、それによって
Chad

201

番号。

回避策は、out / refパラメーターがなく、現在のメソッドを呼び出すだけの別のメソッドでオーバーロードすることです。

public bool SomeMethod(out string input)
{
    ...
}

// new overload
public bool SomeMethod()
{
    string temp;
    return SomeMethod(out temp);
}

更新:C#7.0を使用している場合は、以下を簡素化できます。

// new overload
public bool SomeMethod()
{
    return SomeMethod(out _);    // declare out as an inline discard variable
}

(これを指摘してくれた@Oskar / @Reinerに感謝します。)


6
temp / dummyを宣言するよりもエレガントなソリューションのアイデアはありますか?
Louis Rhys、2007

20
それについてエレガントではないものは何ですか?私には完全にまともです。
ニュートリノ

27
多分まともですが、エレガントは間違いなく別のリーグです。より良い解決策がないという事実は、これが法令による最先端であることを意味しません。
o0 '。

7
@ o0 'を押し続けます。C#7.0では、これを行うことができますreturn SomeMethod(out string temp)。もっとここを参照してください:blogs.msdn.microsoft.com/dotnet/2016/08/24/...
オスカー

7
C#7.0では、あなたは次のように一時的な書き込み専用の変数を使用することができます:return SomeMethod(out _);
ライナー

64

いいえ。ただし、次のように、オプションのパラメーターに汎用テンプレートクラスをメソッドで使用することは、別の優れた代替策です。

public class OptionalOut<Type>
{
    public Type Result { get; set; }
}

その後、次のように使用できます。

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

19
これは非常に合理的な解決策ですが、コンパイラがメソッドを終了する前に出力パラメータを割り当てるという要件を強制しないことに注意してください。
ケン・スミス

2
私はそれが好きですが、新しいクラスを作成したくない場合は、単一の要素の配列を渡すことでシミュレートできます。
zumalifeguard 2015

30

これを行う方法は実際にはC#で許可されています。これはC ++に戻り、むしろC#の優れたオブジェクト指向構造に違反します。

この方法は注意して使用してください!

オプションのパラメーターを使用して関数を宣言して記述する方法は次のとおりです。

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.
    }
}

次に、次のような関数を呼び出します。

unsafe { OptionalOutParameter(); } // does nothing
int MyInteger = 0;
unsafe { OptionalOutParameter(&MyInteger); } // pass in the address of MyInteger.

これをコンパイルするには、プロジェクトオプションで安全でないコードを有効にする必要があります。これは、通常は使用すべきではない本当にハッキーなソリューションですが、奇妙で難解な、神秘的で管理にインスパイアされた決定の場合、C#でオプションの出力パラメーターが本当に必要な場合は、これでそれを実行できます。


6

ICYMI:ここに列挙されているC#7.0の新機能に含まれている「破棄」は、_の形式の出力パラメーターとして許可され、不要なパラメーターを無視できるようになりました。

p.GetCoordinates(out var x, out _); // I only care about x

PS「out var x」の部分と混同されている場合は、リンクの「Out Variables」に関する新機能もお読みください。


それは_または* "p.GetCoordinates(out int x、out *); // xのみ
Onur

ドキュメントの古いバージョンを探していたようです。
Onur Topal

2

いいえ、Action代わりにデリゲート(例:)を使用できます。

オプションの出力パラメーターが必要だと思った状況に直面したときのRobin Rの答えに一部触発され、代わりにActionデリゲートを使用しました。私は彼のサンプルコードを借りてAction<int>、違いと類似点を示すために使用するために修正しました:

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

これには、オプション変数が通常のintとしてソースに表示されるという利点があります(コンパイラーは、ユーザー定義クラスで明示的にラップするのではなく、クロージャークラスで変数をラップします)。

コンパイラーはAction、関数呼び出しが終了する前にが呼び出されると想定できないため、変数を明示的に初期化する必要があります。

すべてのユースケースに適しているわけではありませんが、実際のユースケース(単体テストにデータを提供する関数、および新しい単体テストが戻り値に存在しない内部状態へのアクセスを必要とした場合)にはうまく機能しました。


0

C#6.0以下の場合、outパラメーターなしでオーバーロードされたメソッドを使用して、outパラメーター付きのメソッドを呼び出します。C#4.0にオプションの出力パラメーターを含めることができるかどうかを特に尋ねられたときに、.NET Core用のC#7.0がこのスレッドの正しい答えである理由がわかりません。答えはいいえだ!


-2

これはどうですか?

public bool OptionalOutParamMethod([Optional] ref string pOutParam)
{
    return true;
}

C#からパラメーターに値を渡す必要がありますが、これはオプションの参照パラメーターです。


8
「C#からパラメーターに値を渡す必要があります」...これはオプションではありません。
Arturo

C#は[Optional]注釈を無視します。これは役に立ちません。
ToolmakerSteve 2017年

-4
void foo(ref int? n)
{
    return null;
}

1
コンセプトを簡単に理解できるように、コードに説明を追加してください
techspider

1
このコードは質問に回答する場合がありますが、質問に回答する理由方法に関する追加のコンテキストを提供すると、長期的な価値が大幅に向上します。回答を編集して、説明を追加してください。
Toby Speight 2016年

2
メソッドの戻り値の型が無効であるため、構文エラーになります。また、質問には答えません。
Nathan Montez 2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.