В чем разница между dynamic (C # 4) и var?

199

Я прочитал тонну статей об этом новом ключевом слове, которое поставляется с C # v4, но я не мог понять разницу между «dynamic» и «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свойство (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;}} dynamic (X) s = GetSpecialX (); Вызывающая строка test = 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 ' тип определяется компилятором во время компиляции, тогда как при использовании ' ключевого слова dynamic » тип определяется средой выполнения.
'Ключевое слово 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, 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 обращается с ними обоими после компиляции. Спасибо.
Kings
12

Одно большое отличие - вы можете иметь динамический тип возврата.

dynamic Foo(int x)
{
    dynamic result;

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

    return result;
}
user2382351
источник
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 просматривает ваши данные с правой стороны, а затем во время компиляции определяет тип данных с левой стороны. Другими словами, ключевое слово var просто спасает вас от набора множества вещей. Посмотрите на изображение ниже, где, когда мы дали строковые данные, а переменная x показывает строковый тип данных в моей подсказке.

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

С другой стороны, динамическое ключевое слово для совершенно другой цели. Динамические объекты оцениваются во время выполнения. Например, в приведенном ниже коде свойство «Длина» существует или не оценивается во время выполнения. Я специально набрал маленькую букву «l», поэтому эта программа скомпилировалась нормально, но при ее фактическом выполнении выдает ошибку, когда свойство «длина» был назван (МАЛЕНЬКИЕ "Я").

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

Шивпрасад Койрала
источник
2

Динамическая переменная и переменная var могут хранить значения любого типа, но для их инициализации требуется переменная во время объявления.

Компилятор не имеет никакой информации о «динамическом» типе переменной. var безопасен для компилятора, т.е. компилятор имеет всю информацию о сохраненном значении, поэтому он не вызывает проблем во время выполнения.

Динамический тип может быть передан в качестве аргумента функции, а функция также может его вернуть. Тип var не может быть передан в качестве аргумента функции, а функция не может возвращать тип объекта. Переменная этого типа может работать в той области, где она определена.

В случае динамического приведения не требуется, но вам нужно знать свойство и методы, относящиеся к хранимому типу, тогда как для var нет необходимости в приведении, потому что компилятор имеет всю информацию для выполнения операции.

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

var: полезно при получении результата из запросов linq. В 3.5 Framework он введен для поддержки функции linq.

Ссылка: консультирование

Абхишек Галоут
источник
2
  1. Var и динамический тип определяют.
  2. var во время компиляции, а динамический во время выполнения.
  3. в объявлении и инициализации var оба являются обязательными, как постоянная переменная, в то время как
  4. в динамической инициализации может быть во время выполнения, как переменные только для чтения.
  5. в типе var, какой бы тип ни был решен во время инициализации, не может измениться, но
  6. Динамический может принимать любой тип, даже пользователь определяет тип данных.
ггг
источник
1

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

Картик М
источник
1
  1. Ключевое слово Var (неявная типизированная локальная переменная) используется для определения локальных переменных. В случае 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. Потому что он не поддерживает лямбда-выражения, методы расширения и анонимные методы.

kuttychutty
источник
1

Вот отличия

  • var статически типизирован (время компиляции), динамически типизирован (время выполнения)

  • Переменная, объявленная как var, может использоваться только локально, динамические переменные могут передаваться в качестве параметров функции (сигнатура функции может определять параметр как динамический, но не var).

  • При динамическом разрешении свойств происходит во время выполнения, и это не относится к var, что означает, что во время компиляции любая переменная, объявленная как динамическая, может вызывать метод, который может существовать или не существовать, и поэтому компилятор не будет выдавать ошибку.

  • Приведение типов с помощью var невозможно, но возможно с помощью динамического (вы можете привести объект как динамический, но не как var).

Арун Виджайрагхаван

Арун Виджайрагхаван
источник