В чем разница между 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;
}

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. Потому что он не поддерживает лямбда-выражения, методы расширения и анонимные методы.


1

Вот отличия

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

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

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

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

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.