動的(C#4)と変数の違いは何ですか?


199

C#v4に同梱されているその新しいキーワードに関する記事をたくさん読みましたが、「動的」と「var」の違いを理解できませんでした。

この記事は私にそれについて考えさせましたが、私はまだ違いを見ることができません。

「var」はローカル変数としてのみ使用できますが、ローカルとグローバルの両方として動的に使用できますか?

動的キーワードなしでいくつかのコードを表示してから、動的キーワード付きで同じコードを表示できますか?

回答:


455

var静的に型付けされています-コンパイラとランタイムは型を知っています-それらはいくつかの入力を節約します...以下は100%同一です:

var s = "abc";
Console.WriteLine(s.Length);

そして

string s = "abc";
Console.WriteLine(s.Length);

発生したのは、コンパイラs(イニシャライザからの)文字列である必要があると判断したことだけです。どちらの場合も、(IL)でs.Length(インスタンス)string.Lengthプロパティを意味します。

dynamicある非常に異なる獣。これはに最も似てobjectいますが、動的ディスパッチを使用します。

dynamic s = "abc";
Console.WriteLine(s.Length);

ここでsは、と入力されています。それは知りませんstring.Length、それはわからないので、についてのsコンパイル時に。たとえば、次のコードもコンパイルされます(実行されません)。

dynamic s = "abc";
Console.WriteLine(s.FlibbleBananaSnowball);

実行時(のみ)に、プロパティをチェックFlibbleBananaSnowballます-プロパティを見つけることができず、スパークのシャワーで爆発します。

を使用するとdynamic、プロパティ、メソッド、演算子などは、実際のオブジェクトに基づいて、実行時に解決されます。COM(ランタイムのみのプロパティを持つことができる)、DLR、またはのような他の動的システムとの通信に非常に便利ですjavascript


3
興味深い質問は、静的に宣言されたクラスの動的な祖先があるかどうかです。例:クラスX {public int Y {get; set;}} dynamic(X)s = GetSpecialX(); 文字列テストを呼び出す= sY; コンパイラーはYについて知っているため、コンパイラー・エラーを生成しますが、ストリングtest2 = sZは正常にコンパイルされ、実行時にチェックされます。そのような半動的なクラスの多くの価値を考えることができました!
mmmmmmmm

@rstevens-IIRC、動的な動作をインターフェイスを介して追加できます(ただし、C#で動的な型を実装するための直接的な言語サポートはありません-動的な型を使用するだけです)。これは非現実的ではありません... p
マークグラベル

ただしvar、サブタイプと暗黙のキャストのために、望ましくないタイプが推測される場合があることに注意することが重要です。つまりvar暗黙のキャストが発生したときに、予想よりも静的に異なる型を解決した可能性があります(特に、より一般的な型に解決されますが、これに限定されません)。些細な例はobject x = ""vs. var x = ""vs. var x = "" as objectですが、他のより卑劣な(そして現実的な)ケースが発生し、微妙なバグを引き起こす可能性があります。

Marcの良い例をさらに詳しく説明するために、最初のケース(静的タイプを使用)では、コンパイラーWriteLine、呼び出す多くのオーバーロードのどれを呼び出すかを正確に認識しています。この「バインディング」はコンパイル時に発生します。以下の場合にはdynamic、のタイプが.Lengthある必要がありdynamicすぎて、それはそれはの過負荷(全てであれば)決定され、実行時までではありませんWriteLineフィット最高。バインディングは実行時に行われます。
Jeppe Stig Nielsen

4
varVisual Studioでキーワードにカーソルを合わせると、推論されている実際のタイプが表示されます。コンパイル時に型がわかっていることを示します。
Christian Fredh 2013

56

varで宣言された変数は、暗黙的型付けされます。dynamicで宣言された変数は動的に型付けされます。この機能は、RubyやPythonなどの動的言語をサポートするためにCLRに追加されました。

これは、動的宣言は実行時に解決され、var宣言はコンパイル時に解決されることを意味します。


42

dynamicvarの違いについて説明します。

dynamic d1;
d1 = 1;
d1 = "http://mycodelogic.com";

これは機能します。コンパイラーは、動的変数のタイプを再作成できます。
最初にタイプを整数として作成し、その後コンパイラーがタイプを文字列として再作成します
が、varの場合

var v1;  // Compiler will throw error because we have to initialized at the time of declaration  
var v2 = 1; // Compiler will create v1 as **integer**
v2 = "Suneel Gupta"; // Compiler will throw error because, compiler will not recreate the type of variable 


キーワード' var ' を使用する場合、タイプはコンパイラーによってコンパイル時に決定されますが、 ' dynamic 'キーワードを使用する場合、タイプはランタイムによって決定されます。
' var 'キーワードは、コンパイラーが初期化式から型を判別できる、強く暗黙的に型付けされたローカル変数です。LINQプログラミングを行うときに非常に役立ちます。
コンパイラーには、変数の動的タイプに関する情報がありません。そのため、コンパイラはインテリジェンスを表示しません。
コンパイラーは、var 型の格納された値に関するすべての情報を持っているため、コンパイラーはインテリジェンスを表示します。
動的型は関数引数として渡すことができ、関数はオブジェクト型も返すことができますが

var型は関数引数として渡すことができず、関数はオブジェクト型を返すことができません。このタイプの変数は、それが定義されたスコープで機能します。


14

varは、静的型検査(早期バインディング)が適用されることを意味します。dynamicは、動的型チェック(遅延バインディング)が適用されることを意味します。コードに関しては、次のことを考慮してください。

class Junk
{
    public void Hello()
    {
        Console.WriteLine("Hello");
    }
}

class Program
{
    static void Main(String[] args)
    {
        var a = new Junk();
        dynamic b = new Junk();

        a.Hello();

        b.Hello();
    }
}

これをコンパイルしてILSpyで結果を調べると、コンパイラーがbからのHello()への呼び出しを処理するレイトバインディングコードを追加したことがわかりますが、aにはアーリーバインディングが適用されているため、aはHello () 直接。

例(ILSpy分解)

using System;
namespace ConsoleApplication1
{
    internal class Junk
    {
        public void Hello()
        {
            Console.WriteLine("Hello");
        }
    }
}

using Microsoft.CSharp.RuntimeBinder;
using System;
using System.Runtime.CompilerServices;
namespace ConsoleApplication1
{
    internal class Program
    {
        [CompilerGenerated]
        private static class <Main>o__SiteContainer0
        {
            public static CallSite<Action<CallSite, object>> <>p__Site1;
        }
        private static void Main(string[] args)
        {
            Junk a = new Junk();      //NOTE: Compiler converted var to Junk
            object b = new Junk();    //NOTE: Compiler converted dynamic to object
            a.Hello();  //Already Junk so just call the method.

                          //NOTE: Runtime binding (late binding) implementation added by compiler.
            if (Program.<Main>o__SiteContainer0.<>p__Site1 == null)
            {
                Program.<Main>o__SiteContainer0.<>p__Site1 = CallSite<Action<CallSite, object>>.Create(Binder.InvokeMember(CSharpBinderFlags.ResultDiscarded, "Hello", null, typeof(Program), new CSharpArgumentInfo[]
                {
                    CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
                }));
            }
            Program.<Main>o__SiteContainer0.<>p__Site1.Target(Program.<Main>o__SiteContainer0.<>p__Site1, b);
        }
    }
}

違いを発見するためにできる最善のことは、このような小さなコンソールアプリを自分で作成し、ILSpyで自分でテストすることです。


コンパイル後にILが両方を処理する方法に関するすばらしい基本的な例。ありがとう。
キングス

12

1つの大きな違い-動的な戻り値の型を使用できます。

dynamic Foo(int x)
{
    dynamic result;

    if (x < 5)
      result = x;
    else
      result = x.ToString();

    return result;
}

10

以下は、Dynamic(4.0)とVarの違いを示す簡単な例です。

dynamic  di = 20;
dynamic ds = "sadlfk";
var vi = 10;
var vsTemp= "sdklf";

Console.WriteLine(di.GetType().ToString());          //Prints System.Int32
Console.WriteLine(ds.GetType().ToString());          //Prints System.String
Console.WriteLine(vi.GetType().ToString());          //Prints System.Int32
Console.WriteLine(vsTemp.GetType().ToString());      //Prints System.String

**ds = 12;**   //ds is treated as string until this stmt now assigning integer.

Console.WriteLine(ds.GetType().ToString());          **//Prints System.Int32**

**vs = 12**; //*Gives compile time error* - Here is the difference between Var and Dynamic. var is compile time bound variable.

シヴァ・マミディ


2
私の印象は**、コード例の文字の存在は強調のみを示すことを意図しており、実際に機能するコードの一部を意図するものではないということです。
DavidRR

7

var コンパイラに正しい型を推測させる通常の型宣言の省略形です。

dynamic 新しい(静的)タイプであり、すべてのチェックはコンパイラーではなく実行時に行われます。


4

varで宣言された変数の型はコンパイラによって決定されます。これは、型の名前を指定するショートカットであり、それ以上はありません。

ただし、動的は実行時に決定され、コンパイラーは実際の型を認識しません。その変数を使用したすべてのメソッド/フィールド/プロパティアクセスは、実行時に計算されます。


3

これは実用的なデモンストレーションでvarVS について語る素晴らしいyoutubeビデオですDynamic

以下は、スナップショットの詳細な説明です。

Varは早期にバインドされ(静的にチェックされます)、Dynamicは遅くバインドされます(動的に評価されます)。

Varキーワードは、右側のデータを調べ、コンパイル時に左側のデータ型を決定します。つまり、varキーワードは、多くの入力を節約するだけです。文字列データとx変数を指定すると、ツールチップに文字列データタイプが表示される以下の画像をご覧ください。

ここに画像の説明を入力してください

一方、動的キーワードは完全に異なる目的のためです。動的オブジェクトは実行時に評価されます。たとえば、次のコードでは、実行時に「Length」プロパティが存在するかどうかが評価されます。わざと小さな「l」を入力したので、このプログラムはうまくコンパイルされましたが、実際に実行すると、「length」プロパティのときにエラーが発生しました呼び出されました(SMALL "l")。

ここに画像の説明を入力してください


2

動的変数と変数変数はどちらも任意のタイプの値を格納できますが、宣言時に「var」を初期化するために必要です。

コンパイラーには、「動的」タイプの変数に関する情報がありません。varはコンパイラセーフです。つまり、コンパイラには格納された値に関するすべての情報が含まれているため、実行時に問題が発生しません。

動的な型は関数の引数として渡すことができ、関数はそれを返すこともできます。Var型は関数の引数として渡すことができず、関数はオブジェクト型を返すことができません。このタイプの変数は、それが定義されたスコープで機能します。

動的キャストの場合は必須ではありませんが、ストアドタイプに関連するプロパティとメソッドを知っている必要があります。一方、varの場合は、コンパイラーが操作を実行するためのすべての情報を持っているため、キャストする必要はありません。

dynamic:リフレクションまたは動的言語サポートを使用してコーディングする場合、またはCOMオブジェクトを使用してコーディングする場合に便利です。必要なコードの量が少ないためです。

var:linqクエリから結果を取得するときに役立ちます。3.5フレームワークでは、linq機能をサポートするために導入されています。

参考:カウンセリングビャビ


2
  1. Varと動的定義タイプ。
  2. コンパイル時のvarと動的時のvarは実行時です。
  3. var宣言と初期化では、定数変数のように両方とも必須ですが、
  4. 動的初期化では、実行時に読み取り専用変数のようにすることができます。
  5. var型では、初期化時に決定されるすべての型は初期化を次に変更できませんが、
  6. dynamicは、ユーザー定義のデータ型でも任意の型を採用できます。

1

dynamicとvarを混同しないでください。varを使用してローカル変数を宣言することは、コンパイラに式から特定のデータ型を推測させる構文上のショートカットにすぎません。varキーワードはメソッド内のローカル変数の宣言にのみ使用でき、dynamicキーワードはローカル変数、フィールド、および引数に使用できます。式をvarにキャストすることはできませんが、式を動的にキャストすることはできます。動的で宣言された変数を初期化する必要はありませんが、varを使用して宣言された変数を明示的に初期化する必要があります。


1
  1. Var(Implicit typed local variable)キーワードは、ローカル変数を定義するために使用されます。Varの場合、基礎となるデータ型は、初期割り当てに基づいてコンパイル時にそれ自体で決定されます。Vartypeで初期割り当てが行われると、強く型付けされます。Var型と互換性のない値を格納しようとすると、コンパイル時にエラーが発生します。

例:

Var strNameList=new List<string>(); By using this statement we can store list of names in the string format. 
strNameList.add("Senthil");
strNameList.add("Vignesh");

strNameList.add(45); // This statement will cause the compile time error.

ただし、動的型では、基になる型は実行時にのみ決定されます。動的データ型はコンパイル時にチェックされず、厳密に型指定もされません。動的型に任意の初期値を割り当ててから、新しい型に再割り当てすることができます。その寿命の間の価値。

例:

dynamic test="Senthil";
Console.Writeline(test.GetType())  // System.String

test=1222;
Console.Writeline(test.GetType())  // System.Int32

test=new List<string>();
Console.Writeline(test.GetType())  //System.Collections.Generic.List'1[System.String]

IntelliSenseのサポートも提供していません。linqで作業する場合も、より良いサポートを提供していません。ラムダ式、拡張メソッド、匿名メソッドをサポートしていないためです。


1

ここに違いがあります

  • varは静的に型指定(コンパイル時)、動的は動的に型指定(実行時)

  • varとして宣言された変数はローカルでのみ使用でき、動的変数はparamsとして関数に渡すことができます(関数シグネチャはparamを動的ではなくvarとして定義できます)。

  • 動的の場合、プロパティの解決は実行時に行われますが、varの場合はそうではありません。つまり、動的に宣言された変数は、存在する場合と存在しない場合があるメソッドを呼び出すことができるため、コンパイラはエラーをスローしません。

  • varで型キャストすることはできませんが、dynamicで可能です(オブジェクトをvarとしてではなくdynamicとしてキャストできます)。

アルン・ビジャイラガハヴァン

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.