Яка різниця між динамічним (C # 4) та var?


199

Я прочитав безліч статей про те нове ключове слово, яке постачається за допомогою C # v4, але я не зміг визначити різницю між "динамічним" та "вар".

Ця стаття змусила мене замислитися над цим, але я все ще не бачу різниці.

Ви можете використовувати "var" лише як локальну змінну, але динамічну як локальну, так і глобальну?

Чи можете ви показати якийсь код без динамічного ключового слова, а потім показати той самий код з динамічним ключовим словом?

Відповіді:


455

varвводиться статично - компілятор і час виконання знають тип - вони просто заощадять вас, набравши текст ... наступні на 100% ідентичні:

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

і

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

Все, що сталося, було те, що компілятор з'ясував, що це sповинен бути рядок (від ініціалізатора). В обох випадках він знає (в IL), що s.Lengthозначає string.Lengthвластивість (instance) .

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;}} динамічний (X) s = GetSpecialX (); Виклик рядкового тесту = sY; створило б помилку компілятора, оскільки компілятор знає про Y, але рядок test2 = sZ складе добре і перевіриться під час виконання. Я міг би придумати велику цінність таких напівдинамічних занять!
мммммммммм

@rstevens - IIRC, ви можете додати динамічну поведінку через інтерфейс (хоча немає прямої мовної підтримки для реалізації динамічних типів у C # - лише їх споживання), тому це нереально ... о веселощі, яку ми могли б мати; p
Марк Гравелл

Хоча важливо зауважити, що іноді varможна зробити висновок про типи, які можуть не бути бажаними через підтипи та неявні касти. Тобто, varможливо, він вирішив тип, статично інший, ніж очікувалося, коли трапляються неявні касти (особливо це стосується більш загального типу, але це не обмежується). Тривіальний приклад object x = ""проти var x = ""проти var x = "" as object, але і інші більш хитрі (і реалістичні) випадки можуть мати місце і можуть викликати тонкі помилки.

Щоб детальніше розповісти про хороший приклад Марка, у першому випадку (зі статичним типом) компілятор точно знає, яку з багатьох перевантаженьWriteLine викликати. Це "прив'язка" відбувається під час компіляції. У випадку з dynamicтипом .Lengthмає бути dynamicзанадто великим, і лише до часу виконання рішення не буде вирішено, яке перевантаження (якщо воно взагалі є) WriteLineпідходить найкращим чином. Прив’язка відбувається під час виконання.
Джеппе Стіг Нільсен

4
Коли ви наведіть varключове слово в Visual Studio, відображається фактичний тип, який робиться для висновку. Показує, що тип відомий під час компіляції.
Крістіан Фред

56

Змінні, оголошені з var , неявно, але статично набрані. Змінні, оголошені динамічно , динамічно набираються. Ця можливість була додана до CLR для підтримки таких динамічних мов, як Ruby та Python.

Додам, що це означає, що динамічні декларації вирішуються під час виконання, а декларації var вирішуються під час компіляції.


42

Я збираюся пояснити різницю між динамічним та вар .

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 " тип визначає компілятор під час компіляції, тоді як при використанні " динамічного " ключового слова тип визначається часом виконання.
Ключове слово ' var ' - локальна змінна з сильно неявним набором, для якої компілятор може визначити тип із виразу ініціалізації - дуже корисний під час програмування LINQ.
У компілятора немає жодної інформації про динамічний тип змінної. тому компілятор не проявить ніякого інтелекту.
компілятор має всю інформацію про збережене значення типу var, тому компілятор покаже інтелект.
динамічний тип може передаватися як аргумент функції, а функція також може повернути тип об'єкта
Але тип
var не може бути переданий як аргумент функції і функція не може повернути тип об'єкта. Цей тип змінної може працювати в тій області, де вона визначена.


14

var означає, що застосовується статична перевірка типу (раннє зв'язування). динамічне означає, що застосовується динамічна перевірка типу (пізня прив'язка). Щодо коду, пропонуйте наступне:

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, ви побачите, що компілятор додав якийсь пізній код прив'язки, який буде обробляти виклик Hello () з b, тоді як, оскільки швидке прив'язування було застосовано до a, може викликати привіт () безпосередньо.

наприклад (розбирання 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.


чудовий базовий приклад того, як ІЛ ставиться до обох після компіляції. Дякую.
Королі

12

Одна велика різниця - ви можете мати динамічний тип повернення.

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

Це приємне відео на YouTube, яке розповідає про varVS Dynamicз практичною демонстрацією.

Нижче детальніше пояснення із знімком.

Вар є ранньою прив'язкою (статично перевіряється), а динамічний - пізно прив'язаним (динамічно оцінюється).

Ключове слово Var розглядає дані правої сторони, а потім під час компіляції визначає тип даних ліворуч. Іншими словами, ключове слово var просто заощаджує вас, набираючи багато речей. Подивіться на зображення нижче, коли, коли ми надали рядкові дані, а змінна x показує тип рядкових даних у моєму підказці.

введіть тут опис зображення

З іншого боку, динамічне ключове слово має зовсім іншу мету. Динамічні об'єкти оцінюються під час виконання. Наприклад, у наведеному нижче коді властивість "Length" існує або не оцінюється під час виконання. Я спеціально набрав невеликий "l", тому ця програма складена штрафом, але коли вона насправді виконала, вона викинула помилку, коли властивість "length" називався (МАЛИЙ "л").

введіть тут опис зображення


2

динамічна змінна та змінна var можуть зберігати будь-який тип значення, але його потрібно ініціалізувати 'var' під час оголошення.

Компілятор не має жодної інформації про "динамічний" тип змінної. var є безпечним для компілятора, тобто компілятор має всю інформацію про збережене значення, так що він не викликає жодних проблем під час виконання.

Динамічний тип може передаватися як аргумент функції, а функція також може повернути його. Тип Var не може передаватися як аргумент функції, а функція не може повернути тип об'єкта. Цей тип змінної може працювати в тій області, де вона визначена.

У разі динамічного кастингу не потрібно, але вам потрібно знати властивість та методи, пов'язані із збереженим типом, тоді як для var Не потрібно передавати, оскільки компілятор має всю інформацію для виконання операції.

динамічний: корисний при кодуванні за допомогою відображення або підтримки динамічної мови або з об’єктами COM, оскільки нам потрібно записати меншу кількість коду.

var: Корисно для отримання результатів із запитів linq. У 3.5 рамках він вводить для підтримки функцію linq.

Довідка: Консультуванняб'ябхі


2
  1. Варіантний та динамічний тип визначення.
  2. var під час компіляції, тоді як динамічні знаходяться під час виконання
  3. у var-оголошенні та ініціалізації обидва є обов'язковими, як константа змінної while
  4. в динамічній ініціалізації може бути час виконання, як змінні, що читаються тільки.
  5. у вар-типі незалежно від типу, який вирішено під час ініціалізації не можна змінити наступним, але
  6. Динамічний може приймати будь-який тип, навіть визначає тип даних.

1

Не плутайте динаміку та вар. Оголошення локальної змінної за допомогою var - це лише синтаксичний ярлик, у якому компілятор виводить з виразу конкретний тип даних. Ключове слово var може використовуватися лише для оголошення локальних змінних всередині методу, тоді як динамічне ключове слово може використовуватися для локальних змінних, полів та аргументів. Ви не можете передавати вираз var, але ви можете надати вираз динамічному. Ви повинні явно ініціалізувати змінну, оголошену за допомогою var, тоді як вам не доведеться ініціалізувати змінну, оголошену динамічним.


1
  1. Ключове слово Var (Implicit - локальна змінна), що використовується для визначення локальних змінних. У випадку Var тип базового типу даних визначається під час компіляції на основі початкового призначення. Після того, як початкове призначення було виконано з типом Var, тоді це стане сильно набраним. Якщо ви спробуєте зберегти будь-яке несумісне значення з типом 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, може використовуватися лише локально, динамічні змінні можуть передаватися як парами до функції (підпис функції може визначати парам як динамічний, але не як var).

  • з динамічною роздільною здатністю властивостей відбувається під час виконання, і це не так з var, що означає, що під час компіляції будь-яка змінна, оголошена динамічною, може викликати метод, який може бути, а може і не існувати, і тому компілятор не видасть помилку.

  • Введення кастингу з var не можливе, але можливе динамічне (ви можете передавати об'єкт як динамічний, але не як var).

Арун Віджарагхаван

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.