2016-04-13 13 views
3

ダイナミック変数がメソッド呼び出しの引数として使用されている場合、コンパイラが関数の戻り値の型をチェックしない理由を教えてもらえますか?メソッドの引数として動的変数を使用するとコンパイラのチェックが無効になる

class Program 
{ 
    static void Main(string[] args) 
    { 
     // int a = GetAString(1); // Compiler error CS0029 Cannot impilicitly convert type 'string' to 'int' 

     dynamic x = 1; 

     int b = GetAString(x); // No compiler error -> Runtime Binder Exception 

     // int c = (string)GetAString(x); // Compiler error CS0029 Cannot impilicitly convert type 'string' to 'int' 
    } 

    static string GetAString(int uselessInt) 
    { 
     return "abc"; 
    } 
} 
+0

ILSpyのようなツールを使用してプログラムを調べてください。何が起きているのかがわかります。静的な検査はありません。この場合は実行できます。 – Dennis

答えて

2

dynamicを使用すると、コンパイラは動的パラメータを使用する場所でコールサイトを生成します。このコールサイトは、実行時にメソッドを解決しようとします。一致するメソッドが見つからない場合は、例外が発生します。

この例では、コールサイトはxを調べて、それがintであることを確認します。次にGetAStringというメソッドがあり、そのメソッドはintであり、メソッドを見つけて呼び出しを行うコードを生成します。

次に、戻り値をbに割り当てるためのコードを生成します。動的変数を使用すると、式全体がランタイム評価を必要とするため、これはすべて実行時に実行されます。コールサイトでは、stringintに割り当てるコードを生成できるかどうかが確認されます。例外が発生する可能性があります。あなたも、決してintに割り当てるつもりはないですので、数値以外の値を返しているintあなたGetAsString方法にstringを割り当てるように見えるよう

余談として

、あなたの例は、多くの意味がありません。あなたが書く場合:

dynamic x = 1; 
string b = GetAsString(x); 

すべてが動作するはずです。

+0

答えのためにショーンに感謝します。しかし、私はそれについてさらに2つの質問があります。 1)_return_ type intを持つGetAStringという名前のメソッドが存在する場合、コンパイラがチェックしない理由は何ですか?あなたが右に説明するように、私の方法は決して正しいタイプを返すことはありません! 2)別の例として、コンパイラは既存のメソッドを使用しないかどうかをチェックします。int b = GetFromNonExistingMethod(x); - > CS0103 'GetFromNonExistingMethod'という名前は現在のコンテキストに存在しません – Lowder

+1

式に 'dynamic'変数を使用すると、式全体が動的になります。このシナリオでは、すべてのメソッド解決がコンパイル時ではなく実行時に延期されるというルールがあります。 – Sean

+0

@Lowder - 正しいメソッドを見つけるときには、戻り値の型は決して考慮されません。エラーを生成するのはintへの文字列の割り当て*ですが、その代入操作は、呼び出すメソッドがすでに決定されている場合にのみ、後で指定することができます。 –

1

一般的なケースでは、候補者は必ずしもあなたのものほど簡単ではありません。たとえば、次の2つの方法を考えてみてください。

string M(string a) => a; 
char[] M(char[] a) => a;  

最後の変数のタイプとして、このコードはどのようなものを推奨しますか?この時点で

dynamic d = SomeExpression(); 
var s = M(d); 

、C#4の設計者は、選択をしなければならないでしょう:

  1. dynamicの引数で呼び出されたメソッドの戻り値もdynamicそのものであると主張しています。
  2. グループのすべてのメソッドから割り当てることができるタイプを選択します(例:IEnumerable<char>)。

後者のオプションは、本質的にあなたの質問で説明しているものです。 C#のデザイナーは前者のオプションを使いました。その設計上の決定のために考えられる理由が考えられます。

  • たぶん、彼らはあなたが式にdynamicにで選ぶならば、それはあなたがするまで、任意の依存式にdynamicを使用して保存しておきたいだろうということではない可能性が高いだと思いました明示的にオプトアウトすることができます。
  • 複数のディスパッチを可能にするためにdynamicを導入していない可能性がありますので、静的型付けのための規定を追加することでそれをさらに奨励したくありませんでした。
  • おそらく彼らは、これらの規定を含めて仕様を膨らませたり、言語を理解しづらくすると思ったでしょうか。
  • 前者の方が実装が簡単であるかもしれません(既にdynamicの残りの部分が実装されていることを前提としています)、他のオプションが時間や労力に価値がないと判断しました。
  • 多分、C#で実装するのはそれほど簡単ではありません。値型は、一般的なスーパータイプと一致するボクシングを必要とする可能性があります。生のポインタ型は統一された階層から完全に外れています。
関連する問題