web-dev-qa-db-ja.com

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

C#4.0では、オプションのoutまたはref引数を使用できますか?

198
Joe Daley

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

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

固定パラメーター:
属性opt パラメータ修飾子opt タイプ識別子のデフォルト引数opt
default-argument:
=式

  • fixed-parameterdefault-argumentは、オプションのパラメータ、一方、default-argumentなしのfixed-parameter必須パラメーター
  • 必須パラメーターは、formal-parameter-listのオプションのパラメーターの後に表示できません。
  • refまたはoutパラメーターには、default-argumentを含めることはできません。
89
Tomas Petricek

番号。

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

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

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

更新: C#7. がある場合、単純化できます:

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

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

184
Dunc

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

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);
}
63
Robin R

実際には、C#で許可されているこれを行う方法があります。これはC++に戻り、むしろ、C#のNice Object-Oriented構造に違反しています。

このメソッドは注意して使用してください!

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

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#でオプションのoutパラメーターが本当に必要な場合は、まさにこれを行うことができます。

27
wizard07KSU

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

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

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

6
jbdeguzman

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

オプションの出力パラメーターが必要だと思った状況に直面したときのロビン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が呼び出されることを想定できないため、変数を明示的に初期化する必要があります。

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

2
Steve

C#6.0以前の場合、outパラメータなしでオーバーロードされたメソッドを使用して、outパラメータを持つメソッドを呼び出します。 C#4.0にオプションのoutパラメーターを設定できるかどうかを具体的に尋ねられたときに、なぜ。答えはノーです!

0
Mr_CSharp