web-dev-qa-db-ja.com

C#で、returnステートメントの一部としてvoidメソッドを呼び出せないのはなぜですか?

呼び出し側のメソッドの戻り値の型もvoidである場合に、C#がreturnステートメントの一部としてvoidメソッドの呼び出しをサポートしない理由について、正当な理由があるかどうか知りたいです。

public void MethodA() 
{ 
    return; 
}

public void MethodB() 
{
    return MethodA();
}

したがって、通常は次のようになります。

public void MethodMeh() 
{
    if (expression) 
    {
        MethodA();
        return;
    }

    // Do more stuff
}

...代わりにこれを使用できる場合:

public void MethodAwesome() 
{
    if (expression) 
        return MethodA();

    // Do more stuff
}

C#によるvoidの処理方法による言語の制限ですか?

38
Matt Beckman

それは単に方法 言語が定義されている だからです。

メソッドはreturnステートメントを使用して、呼び出し元に制御を返すことができます。 voidを返すメソッドでは、returnステートメントは式を指定できません。voidreturnステートメントには、戻り値を計算する式を含める必要があります。

これは任意の決定であり(おそらくANSI Cと他の子孫との互換性のために作られています)、他の言語は異なる方法で動作します。

たとえば、Pythonでは、すべての関数が値を返します。値なしでreturnステートメントを実行するか、制御を関数の最後に到達させると、return Noneを記述したようになります。

対照的に、Pascalはfunctionの用語を、戻り値を持つサブプログラムに限定しています。何も返さない場合は、代わりにprocedureを使用します。

39
dan04

voidは情報がないことです。返品しても意味がありません。他の一部の言語とは異なり、これは型*ではなく、値でもありません。いいえ、それは実際には制限ではありません。

*そうですね、@ Lucasが指摘しているように。これは情報タイプです。通常の意味でのタイプを実際に表すものではありません。持てません。

28
Ry-

あなたの質問は the void typethe unit type の違いについてです(F#のような関数型言語で最も一般的に見られます) 。

基本的に、voidは実際の型ではありません。リフレクションの目的で System.Void がありますが、実際の型を使用できるほとんどの場所ではvoidを使用できません。型の変数を持つことはできませんvoidおよびジェネリックでは使用できません(たとえFunc<void>を記述できると非常に便利な場合があります)。

一方、F#のunitは実際の型です。値は(単一の)値(()と呼ばれます)なので、Func<void>と同等の値を記述できます(unit -> unit、最初のunitは「パラメータなし」を意味します。これは、Cのパラメータリストにvoidを書き込むのと同様であり、unit型の変数を持つことができます。例えば:

let unitTest (f : unit -> unit) =
    let nothing : unit = f()
    ()

最後の行は、実際にはF#では、明示的にunitを返す必要があることを示しています

7
svick

これは、言語仕様により許可されていません。 ECMA-334(強調鉱山)の15.9.4から:

式を含むreturnステートメントは、値を計算する関数メンバー、つまりnon-void return type、プロパティまたはインデクサーのgetアクセサー、またはユーザー定義の演算子。

4
AlexD

それは言語デザイナーによる選択に帰着します。

型の観点からすると、voidには列挙可能な値がないため、「void」型の値を返すことは意味がありませんか? voidは型または評価コンテキストがないことです。

C#またはJavaで「void」をインスタンス化または返すことはできません。

可能であれば、次のように言うこともできます。

 void i;
 i = (what would go here?)
 return i;

上記は意味がありませんが、あなたが提案するものと同等です。

結局のところ、returnステートメントを使用してvoid returnコンテキストを伝播できると提案することは、単に構文上の問題であり、言語デザイナーによる選択に帰着します。

C#言語仕様 http://msdn.Microsoft.com/en-us/library/aa691305(v = vs.71).aspx (セクション7.1)は言う

何もない。これは、式がvoidの戻り値の型を持つメソッドの呼び出しである場合に発生します。何にも分類されない式は、statement-expressionのコンテキストでのみ有効です(セクション8.6)。

一方、C++デザイナーは、実際には、提案する構成だけを許可することを選択しましたが、これは特に、テンプレートの構文の均一性のためでした。 C++では、テンプレート関数の戻り値の型をテンプレートパラメータにすることができます。 (Stroustrop C++プログラミング言語p 148)これがないと、T型のネストされた関数呼び出しなど、すべての型に対してコンパイルされますが、voidに対してはコンパイルされない一般的なケースがあります。そのため、以下は有効なC++です。

void B() {
  return;
}

void A() {
  return B(); // legal C++ - doesn't yield a value
}

// But even in C++ the next line is illegal
int i = A();

したがって、ステートメント式「return B();」ここで、Bはvoid関数であり、「B(); return;」の単なるショートカットです。そして実際には値を生み出さない、なぜならボイド値などはないからです。

4
codenheim

これには正当な理由があると思います。

コンパイラーは、式を検出すると、既知の式のリストにあるものと一致させようとします。 returnで始まる2種類のステートメントがあると言えます。

  1. return exprexprは、含まれているメソッドの宣言された戻り値の型に割り当て可能な式です。
  2. return他に何もない

これらは似ていても、まったく異なるステートメントです。ただし、特定のケースでは、1つのcanがもう1つにコンパイルされます(foreachwhileにコンパイルされたのと同様に)。したがって、exprが戻り値の型ではない(つまり、void)と判断された場合は常に、return exprexpr; return;のコンパイル先にコンパイルされるというルールを追加できます。

しかし、C#コンパイラの実装者は、通常はstatementsのみが戻り値型を持たない場合に、すべての式が戻り値型を持たないようにする必要があります。これを行った場合、実際の型が必要な場合は常に、型のない式を手動で禁止する必要があります。たとえば、関数呼び出しMyMethod(1, 2, SomethingVoid())の引数として機能する式では、コンパイラはこれらの式のいずれかが型を返さないかどうかをさらにチェックする必要があります。そして、将来C#に追加されるすべての新しい種類の式については、同じチェックを追加する必要があります。

上記は可能ですが、抽象構文ツリー(コンパイル中に生成されたもの)内の非ステートメント式に戻り値の型がないようにする以外に理由はありません。これは、マイナーな構文を可能にするためだけのケースです。構造-そして、もう(キーストロークで)タイプする必要がなく、読むのがより明確な代替手段を持つもの。

結局、それは価値があるように聞こえません。

あなたは実際の質問のタイトルが回答に含まれていないようですが、彼らは正しいことを理解しているかもしれません。あなたは質問のタイトルです

C#がvoidの戻り値の型を持つメソッドを返すことをサポートしないのはなぜですか

実際、C#はこれを許可しますが、あなたが試みている形式ではありません。他の人が答えたようにvoidキーワードを使用すると、メソッドは何も返しません。メソッドを返したいのに何も返さない場合は、次のようにします。

public Action MethodExample()
{
    return () => { Console.WriteLine("Hello World!"); };
}

次に、単純な呼び出しで次のアクションが実行されます。

var action = MethodExample();
action(); // prints Hello World
2
Ian

voidは空です。 C#言語のvoidキーワードは、メソッドが何も返さないことを示します。 voidメソッドが呼び出されると、結果がなく、変数を割り当てることができません。

この説明を参照

1
bumbumpaw