Jaka jest różnica między dynamicznym (C # 4) a var?

199

Przeczytałem mnóstwo artykułów na temat tego nowego słowa kluczowego, które jest dostarczane z C # v4, ale nie mogłem zrozumieć różnicy między „dynamicznym” a „var”.

Ten artykuł zmusił mnie do przemyślenia tego, ale nadal nie widzę żadnej różnicy.

Czy możesz używać „var” tylko jako zmiennej lokalnej, ale dynamicznej zarówno jako lokalnej, jak i globalnej?

Czy możesz pokazać kod bez dynamicznego słowa kluczowego, a następnie pokazać ten sam kod z dynamicznym słowem kluczowym?

Ivan Prodanov
źródło

Odpowiedzi:

455

varma typ statyczny - kompilator i środowisko wykonawcze znają typ - po prostu oszczędzają ci pisania ... następujące elementy są w 100% identyczne:

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

i

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

Wszystko, co się wydarzyło, polegało na tym, że kompilator zorientował się, że smusi to być ciąg znaków (z inicjatora). W obu przypadkach wie (w IL), że s.Lengthoznacza właściwość (instancja) string.Length.

dynamicjest zupełnie inną bestią; jest najbardziej podobny do objectdynamicznej wysyłki:

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

Tutaj sjest wpisany jako dynamiczny . Nie wie o tym string.Length, ponieważ nie wie nic o sczasie kompilacji. Na przykład następujące polecenia również skompilują (ale nie uruchomią):

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

W czasie wykonywania (tylko), to sprawdzić za FlibbleBananaSnowballnieruchomości - uda się go znaleźć, i eksplodować w deszcz iskier.

Za pomocą dynamicwłaściwości / metod / operatorów / itp. Są rozwiązywane w czasie wykonywania na podstawie rzeczywistego obiektu. Bardzo przydatny do rozmowy z COM (który może mieć właściwości tylko w czasie wykonywania), DLR lub innymi systemami dynamicznymi, takimi jak javascript.

Marc Gravell
źródło
3
Ciekawym pytaniem byłoby, czy istnieją dynamiczni przodkowie klas deklarowanych statycznie. Przykład: klasa X {public int Y {get; set;}} dynamic (X) s = GetSpecialX (); Wywołanie ciągu testowego = sY; wygeneruje błąd kompilatora, ponieważ kompilator wie o Y, ale łańcuch test2 = sZ skompiluje się dobrze i zostanie sprawdzony w czasie wykonywania. Mógłbym pomyśleć o dużej wartości takich pół-dynamicznych klas!
mmmmmmmm,
@rstevens - IIRC, możesz dodać dynamiczne zachowanie poprzez interfejs (chociaż nie ma bezpośredniego wsparcia językowego dla implementacji typów dynamicznych w C # - tylko je zużywających), więc nie jest to nierealne ... och, zabawę możemy mieć; - p
Marc Gravell
Chociaż należy zauważyć, że czasami varmożna wywnioskować typy, które mogą nie być pożądane z powodu podtypów i niejawnych rzutów. Oznacza to, że varmógł rozwiązać typ statystycznie inny niż oczekiwano, gdy wystąpią niejawne rzuty (w szczególności na bardziej ogólny typ, ale nie jest to ograniczone do tego). Trywialnym przykładem jest object x = ""vs. var x = ""vs. var x = "" as object, ale mogą wystąpić inne bardziej podstępne (i realistyczne) przypadki, które mogą powodować subtelne błędy.
Aby rozwinąć dobry przykład Marca, w pierwszym przypadku (z typem statycznym) kompilator dokładnie wie, które z wielu przeciążeńWriteLine wywołać. To „wiązanie” ma miejsce podczas kompilacji. W takim przypadku dynamictyp .Lengthmusi być dynamicrównież i dopiero w czasie wykonywania decyduje się, które przeciążenie (jeśli w ogóle) WriteLinepasuje najlepiej. Wiązanie odbywa się w czasie wykonywania.
Jeppe Stig Nielsen
4
Po najechaniu kursorem na varsłowo kluczowe w Visual Studio wyświetlany jest faktyczny typ, który jest wnioskowany. Pokazuje, że typ jest znany w czasie kompilacji.
Christian Fredh
56

Zmienne zadeklarowane za pomocą var są domyślnie, ale statycznie typowane. Zmienne zadeklarowane za pomocą dynamiki są dynamicznie wpisywane. Ta funkcja została dodana do CLR w celu obsługi dynamicznych języków, takich jak Ruby i Python.

Powinienem dodać, że oznacza to, że deklaracje dynamiczne są rozstrzygane w czasie wykonywania, deklaracje var są rozstrzygane w czasie kompilacji.

Hans Van Slooten
źródło
42

Wyjaśnię różnicę między dynamiką a var .

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

To zadziała. kompilator może odtworzyć typ zmiennej dynamicznej .
najpierw tworzy typ jako liczbę całkowitą, a następnie kompilator odtworzy typ jako ciąg znaków,
ale w przypadku 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 


W przypadku użycia słowa kluczowego „ var ” o typie decyduje kompilator w czasie kompilacji, natomiast w przypadku słowa kluczowego „ dynamicznego ” o typie decyduje środowisko wykonawcze.
słowo kluczowe „ var ”, zmienna lokalna o silnym typie domyślnym, dla której kompilator jest w stanie określić typ na podstawie wyrażenia inicjującego - bardzo przydatne podczas programowania LINQ.
Kompilator nie ma żadnych informacji o dynamicznym typie zmiennej. więc kompilator nie pokaże żadnej inteligencji.
kompilator ma wszystkie informacje o przechowywanej wartości typu var, więc kompilator pokaże inteligencję.
typ dynamiczny może być przekazany jako argument funkcji, a funkcja może również zwrócić typ obiektu,
ale nie można przekazać typu
var jako argumentu funkcji, a funkcja nie może zwrócić typu obiektu. Ten typ zmiennej może działać w zakresie, w którym został zdefiniowany.

Suneel Gupta
źródło
14

var oznacza, że ​​stosowane jest sprawdzanie typu statycznego (wczesne wiązanie). dynamiczny oznacza, że ​​stosowane jest dynamiczne sprawdzanie typu (późne wiązanie). Pod względem kodu należy wziąć pod uwagę następujące kwestie:

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

Jeśli to skompilujesz i sprawdzisz wyniki za pomocą ILSpy, przekonasz się, że kompilator dodał jakiś późny kod wiązania, który obsłuży wywołanie Hello () z b, a ponieważ wcześniejsze wiązanie zostało zastosowane do a, a może wywołać Hello () bezpośrednio.

np. (demontaż 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);
        }
    }
}

Najlepszą rzeczą, jaką możesz zrobić, aby odkryć różnicę, jest napisanie sobie małej aplikacji na konsolę, takiej jak ta, i przetestowanie jej samodzielnie za pomocą ILSpy.

Matthew Layton
źródło
świetny podstawowy przykład tego, jak IL traktuje oba po kompilacji. Dzięki.
Królowie
12

Jedna wielka różnica - możesz mieć dynamiczny typ zwrotu.

dynamic Foo(int x)
{
    dynamic result;

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

    return result;
}
użytkownik2382351
źródło
10

Oto prosty przykład, który pokazuje różnicę między Dynamic (4.0) a 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.

Shiva Mamidi

Shiva Mamidi
źródło
2
Mam wrażenie, że obecność **znaków w przykładzie kodu ma na celu jedynie wskazanie wyróżnienia i nie jest częścią rzeczywistego działającego kodu.
DavidRR
7

var jest tylko skrótem dla normalnej deklaracji typu, gdzie pozwalasz kompilatorowi odgadnąć właściwy typ.

dynamic jest nowym (statycznym) typem, w którym wszystkie kontrole są wykonywane w czasie wykonywania, a nie przez kompilator.

gimel
źródło
4

Typ zmiennej zadeklarowanej za pomocą var jest określany przez kompilator, jest to skrót do określania nazwy typu, nic więcej.

Jakkolwiek dynamika jest określana w czasie wykonywania, kompilator nie ma pojęcia o rzeczywistym typie, a wszystkie dostępy do metod / pól / właściwości z tą zmienną zostaną opracowane w czasie wykonywania.

Richard
źródło
3

To fajny film na YouTube, który opowiada o varVS Dynamicz praktyczną demonstracją.

Poniżej znajduje się bardziej szczegółowe objaśnienie z migawką.

Var jest wcześnie wiązany (sprawdzany statycznie), podczas gdy dynamiczny jest późno wiązany (oceniany dynamicznie).

Słowo kluczowe Var sprawdza dane po prawej stronie, a następnie podczas kompilacji decyduje o typie danych po lewej stronie. Innymi słowy, słowo kluczowe var oszczędza Ci pisania wielu rzeczy. Spójrz na poniższy obrazek, gdzie kiedy podaliśmy dane ciągu, a zmienna x pokazuje typ danych ciągu w mojej podpowiedzi.

wprowadź opis zdjęcia tutaj

Z drugiej strony dynamiczne słowo kluczowe ma zupełnie inny cel. Obiekty dynamiczne są oceniane podczas działania. Na przykład w poniższym kodzie właściwość „Długość” istnieje lub nie jest oceniana w czasie wykonywania. Celowo wpisałem małe „l”, więc ten program skompilował się dobrze, ale kiedy faktycznie się uruchomił, wyrzucił błąd, gdy właściwość „długość” został nazwany (SMALL „l”).

wprowadź opis zdjęcia tutaj

Shivprasad Koirala
źródło
2

zarówno zmienna dynamiczna, jak i zmienna var mogą przechowywać dowolny rodzaj wartości, ale jest ona wymagana do zainicjowania „var” w momencie deklaracji.

Kompilator nie ma żadnych informacji o typie zmiennej „dynamicznej”. var jest bezpieczny dla kompilatora, tzn. kompilator ma wszystkie informacje o przechowywanej wartości, dzięki czemu nie powoduje żadnych problemów w czasie wykonywania.

Typ dynamiczny można przekazać jako argument funkcji, a funkcja może go również zwrócić. Typ zmiennej nie może być przekazany jako argument funkcji, a funkcja nie może zwrócić typu obiektu. Ten typ zmiennej może działać w zakresie, w którym został zdefiniowany.

W przypadku dynamicznego rzutowania nie jest wymagane, ale musisz znać właściwość i metody związane z typem przechowywanym, natomiast dla var Nie trzeba rzutować, ponieważ kompilator ma wszystkie informacje do wykonania operacji.

dynamiczny: Przydatny przy kodowaniu z wykorzystaniem refleksji lub obsługi języka dynamicznego lub z obiektami COM, ponieważ wymagamy mniejszej ilości kodu.

var: Przydatny przy uzyskiwaniu wyników z zapytań linq. W wersji 3.5 wprowadza obsługę Linq.

Odniesienie: Counsellingbyabhi

Abhishek Gahlout
źródło
2
  1. Var i dynamicznie określają typ.
  2. var w czasie kompilacji, podczas gdy dynamiczny w czasie wykonywania.
  3. oba w deklaracji var i inicjalizacji są obowiązkowe jak zmienna stała while
  4. w dynamicznej inicjalizacji może być w czasie wykonywania jak zmienne tylko do odczytu.
  5. w typie var niezależnie od typu, który zostanie ustalony w momencie inicjalizacji nie można zmienić, ale
  6. dynamiczny może przyjąć dowolny typ, nawet typ danych zdefiniowany przez użytkownika.
Ciii
źródło
1

Nie myl dynamiki i var. Zadeklarowanie zmiennej lokalnej za pomocą var jest tylko skrótem składniowym, w którym kompilator wyprowadza określony typ danych z wyrażenia. Słowa kluczowego var można używać tylko do deklarowania zmiennych lokalnych w metodzie, natomiast słowa kluczowego dynamicznego można używać do zmiennych lokalnych, pól i argumentów. Nie możesz rzutować wyrażenia na var, ale możesz rzutować wyrażenie na dynamiczne. Musisz jawnie zainicjować zmienną zadeklarowaną za pomocą var, podczas gdy nie musisz inicjować zmiennej zadeklarowanej dynamicznie.

Kartik M.
źródło
1
  1. Słowo kluczowe Var (zmienna lokalna o typie niejawnym) służy do definiowania zmiennych lokalnych. W przypadku Var typ danych bazowych jest określany w samym czasie kompilacji w oparciu o początkowe przypisanie. zostanie silnie wpisany. Jeśli spróbujesz zapisać dowolną niezgodną wartość z typem Var, spowoduje to błąd czasu kompilacji.

Przykład:

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.

Ale w typie dynamicznym typ bazowy jest określany tylko w czasie wykonywania. Dynamiczny typ danych nie jest sprawdzany w czasie kompilacji, a także nie jest silnie typowany. Możemy przypisać dowolną wartość początkową dla typu dynamicznego, a następnie można ją ponownie przypisać do dowolnego nowego wartość w ciągu swojego życia.

Przykład:

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]

Nie zapewnia również wsparcia IntelliSense. Nie zapewnia lepszego wsparcia, gdy dajemy również pracę z linq, ponieważ nie obsługuje wyrażeń lambda, metod rozszerzenia i metod anonimowych.

kuttychutty
źródło
1

Oto różnice

  • var jest wpisywany statycznie (czas kompilacji), dynamiczny jest dynamicznie wpisywany (czas wykonywania)

  • Zmienna zadeklarowana jako var może być używana tylko lokalnie, zmienne dynamiczne mogą być przekazywane jako parametry funkcji (podpis funkcji może definiować parametr jako dynamiczny, ale nie zmienny).

  • z dynamiką rozdzielczość właściwości zachodzi w czasie wykonywania i tak nie jest w przypadku var, co oznacza, że ​​w czasie kompilacji każda zmienna zadeklarowana jako dynamiczna może wywołać metodę, która może istnieć lub nie, a więc kompilator nie zgłasza błędu.

  • Typ rzutowania z var nie jest możliwy, ale z dynamicznym jest to możliwe (możesz rzutować obiekt tak dynamicznie, ale nie jako var).

Arun Vijayraghavan

Arun Vijayraghavan
źródło