ความแตกต่างระหว่างไดนามิก (C # 4) และ var คืออะไร


199

ฉันได้อ่านบทความเกี่ยวกับคำหลักใหม่ที่จัดส่งด้วย C # v4 แต่ฉันไม่สามารถแยกความแตกต่างระหว่าง "ไดนามิก" และ "var" ได้

บทความนี้ทำให้ฉันคิดเกี่ยวกับมัน แต่ฉันยังไม่เห็นความแตกต่าง

เป็นเพราะคุณสามารถใช้ "var" เป็นตัวแปรโลคอลเท่านั้น แต่เป็นไดนามิคทั้งในท้องถิ่นและทั่วโลก?

คุณสามารถแสดงรหัสที่ไม่มีคำหลักแบบไดนามิกแล้วแสดงรหัสเดียวกันกับคำหลักแบบไดนามิกได้หรือไม่

คำตอบ:


455

varเป็นแบบคงที่ - คอมไพเลอร์และรันไทม์รู้ประเภท - พวกเขาเพียงแค่ช่วยให้คุณพิมพ์ ... ต่อไปนี้เป็นเหมือนกัน 100%:

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

และ

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

สิ่งที่เกิดขึ้นคือคอมไพเลอร์คิดว่าsต้องเป็นสตริง (จาก initializer) ในทั้งสองกรณีมันรู้ (ใน 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คุณสมบัติ / methods / โอเปอเรเตอร์ / etc จะถูกแก้ไขที่ runtimeตามวัตถุจริง มีประโยชน์มากสำหรับการพูดคุยกับ COM (ซึ่งจะมีคุณสมบัติรันไทม์เท่านั้น) DLR หรือระบบพลวัตอื่น ๆ javascriptเช่น


3
คำถามที่น่าสนใจคือถ้ามีบรรพบุรุษแบบไดนามิกของคลาสที่ประกาศแบบคงที่ ตัวอย่าง: คลาส X {public int Y {get; set;}} dynamic (X) s = GetSpecialX (); การเรียก string test = sY; จะสร้างข้อผิดพลาดคอมไพเลอร์เพราะคอมไพเลอร์รู้เกี่ยวกับ Y แต่สตริง test2 = sZ จะรวบรวมดีและถูกตรวจสอบในเวลาทำงาน ฉันคิดว่ามีค่ามากสำหรับคลาสครึ่งไดนามิกเช่นนี้!
mmmmmmmm

@rstevens - IIRC คุณสามารถเพิ่มพฤติกรรมแบบไดนามิกผ่านทางอินเทอร์เฟซ (แม้ว่าจะไม่มีการสนับสนุนภาษาโดยตรงสำหรับการใช้งานประเภทไดนามิกใน C # - เพียงแค่ใช้พวกมัน) ดังนั้นนี่ไม่ใช่ความจริง ... โอ้ความสนุกที่เรามี; - p
Marc Gravell

แม้ว่าจะเป็นสิ่งสำคัญที่จะต้องทราบว่าบางครั้งvarสามารถอนุมานประเภทที่อาจไม่ต้องการเนื่องจากย่อยและปลดเปลื้องโดยนัย นั่นคือvarอาจมีการแก้ไขประเภทที่แตกต่างจากที่คาดไว้เมื่อมีการปลดเปลื้องโดยนัย (โดยเฉพาะอย่างยิ่งกับประเภททั่วไปที่มากขึ้น แต่ไม่ จำกัด เฉพาะสิ่งนี้) ตัวอย่างเล็ก ๆ น้อย ๆ คือobject x = ""vs. vs. var x = ""vs. var x = "" as objectแต่กรณีอื่น ๆ ที่น่าสงสัย (และเป็นจริง) สามารถเกิดขึ้นได้และอาจทำให้เกิดข้อบกพร่องเล็กน้อย

ในการอธิบายเพิ่มเติมเกี่ยวกับตัวอย่างที่ดีของ Marc ในกรณีแรก (ที่มีประเภทแบบคงที่) คอมไพเลอร์จะทราบว่าโอเวอร์โหลดใดของWriteLineการโทรจำนวนมาก "การรวม" นี้เกิดขึ้นขณะคอมไพล์ ในกรณีที่มีdynamicประเภทของ.Lengthจะต้องมีdynamicมากเกินไปและมันไม่ได้จนกว่าจะถึงเวลาทำงานจะตัดสินใจว่าเกินพิกัดใด (ถ้ามีทั้งหมด) ของWriteLineที่ดีที่สุด การรวมเกิดขึ้นขณะรันไทม์
Jeppe Stig Nielsen

4
เมื่อคุณโฮเวอร์varคำสำคัญใน Visual Studio ชนิดที่แท้จริงจะแสดงที่ถูกอนุมาน แสดงให้คุณเห็นว่าเป็นที่รู้จักกันในเวลารวบรวม
Christian Fredh

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, 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.

Shiva Mamidi


2
ความประทับใจของฉันคือการปรากฏตัวของ**ตัวละครในตัวอย่างของรหัสมีจุดประสงค์เพื่อบ่งบอกถึงการเน้นเท่านั้น
DavidRR

7

var เป็นเพียงการจดชวเลขสำหรับการประกาศประเภทปกติที่คุณให้ผู้แปลเดาประเภทที่ถูกต้อง

dynamic เป็นชนิดใหม่ (คงที่) ซึ่งการตรวจสอบทั้งหมดจะทำที่รันไทม์ไม่ใช่โดยคอมไพเลอร์


4

ชนิดของตัวแปรที่ประกาศด้วย var จะถูกกำหนดโดยคอมไพเลอร์มันเป็นทางลัดในการระบุชื่อของประเภทไม่มีอะไรเพิ่มเติม

อย่างไรก็ตามแบบไดนามิกถูกกำหนดที่รันไทม์คอมไพเลอร์ไม่มีความคิดเกี่ยวกับชนิดที่แท้จริงและการเข้าถึงเมธอด / ฟิลด์ / คุณสมบัติทั้งหมดที่มีตัวแปรนั้นจะทำงานเมื่อรันไทม์


3

นี่เป็นวิดีโอ youtube ที่ดีที่พูดถึงvarVS Dynamicด้วยการสาธิตเชิงปฏิบัติ

ด้านล่างนี้เป็นคำอธิบายโดยละเอียดยิ่งขึ้นด้วยภาพรวม

Var ถูกผูกไว้ก่อนหน้านี้ (ตรวจสอบแบบคงที่) ในขณะที่ไดนามิกถูกผูกปลาย (ประเมินแบบไดนามิก)

คำหลัก Var ดูที่ข้อมูลด้านขวาของคุณจากนั้นในช่วงเวลารวบรวมมันจะตัดสินใจเลือกชนิดข้อมูลทางซ้ายมืออีกนัยหนึ่งคำหลัก var คำหลักเพียงช่วยให้คุณพิมพ์สิ่งต่างๆมากมาย ลองดูภาพด้านล่างซึ่งเมื่อเราได้รับข้อมูลสตริงและตัวแปร x แสดงชนิดข้อมูลสตริงในเคล็ดลับเครื่องมือของฉัน

ป้อนคำอธิบายรูปภาพที่นี่

ในทางกลับกันคำสำคัญแบบไดนามิกนั้นมีจุดประสงค์ที่แตกต่างอย่างสิ้นเชิง อ็อบเจ็กต์แบบไดนามิกถูกประเมินระหว่างรันไทม์ ตัวอย่างเช่นในรหัสด้านล่างมีคุณสมบัติ "ความยาว" อยู่หรือไม่ถูกประเมินในระหว่างรันไทม์ฉันได้พิมพ์ตัวอักษร "l" ตัวเล็กดังนั้นโปรแกรมนี้จึงทำการคอมไพล์ได้ดี ถูกเรียก (SMALL "l")

ป้อนคำอธิบายรูปภาพที่นี่


2

ตัวแปรแบบไดนามิกและตัวแปร var สามารถเก็บค่าชนิดใดก็ได้ แต่จำเป็นต้องมีค่าเริ่มต้น 'var' ณ เวลาที่ประกาศ

คอมไพเลอร์ไม่มีข้อมูลเกี่ยวกับตัวแปร 'ไดนามิก' var เป็นคอมไพเลอร์ปลอดภัยเช่นคอมไพเลอร์มีข้อมูลทั้งหมดเกี่ยวกับค่าที่เก็บไว้เพื่อที่จะไม่ทำให้เกิดปัญหาใด ๆ ในเวลาทำงาน

ประเภทไดนามิกสามารถส่งผ่านเป็นฟังก์ชั่นการโต้แย้งและฟังก์ชั่นยังสามารถส่งคืนได้ ไม่สามารถส่งประเภท Var ได้เนื่องจากอาร์กิวเมนต์ของฟังก์ชันและฟังก์ชันไม่สามารถส่งคืนชนิดของวัตถุได้ ตัวแปรประเภทนี้สามารถทำงานในขอบเขตที่กำหนดไว้

ในกรณีของ Dynamic Casting ไม่จำเป็นต้องมี แต่คุณจำเป็นต้องรู้คุณสมบัติและวิธีการที่เกี่ยวข้องกับประเภทที่จัดเก็บในขณะที่สำหรับ var ไม่จำเป็นต้องส่งเนื่องจากคอมไพเลอร์มีข้อมูลทั้งหมดเพื่อดำเนินการ

แบบไดนามิก: มีประโยชน์เมื่อการเข้ารหัสโดยใช้การสะท้อนกลับหรือการสนับสนุนภาษาแบบไดนามิกหรือกับวัตถุ COM เพราะเราต้องการที่จะเขียนรหัสจำนวนน้อย

var: มีประโยชน์เมื่อรับผลลัพธ์จากคิวรี linq ในเฟรมเวิร์ก 3.5 แนะนำให้สนับสนุนฟีเจอร์ linq

การอ้างอิง: Counsellingbyabhi


2
  1. Var และประเภทกำหนดแบบไดนามิก
  2. var ที่เวลาคอมไพล์ขณะที่ไดนามิกเป็นเวลารันไทม์
  3. ในการประกาศ var และการเริ่มต้นทั้งสองจะบังคับเช่นตัวแปรคงที่ในขณะที่
  4. ในการกำหนดค่าเริ่มต้นแบบไดนามิกอาจเป็นเวลาทำงานเช่นตัวแปรแบบอ่านอย่างเดียว
  5. ในประเภท var สิ่งที่ประเภทจะตัดสินใจในเวลาเริ่มต้นไม่สามารถเปลี่ยนแปลงได้ แต่
  6. แบบไดนามิกสามารถนำมาใช้ประเภทใด ๆ แม้ผู้ใช้กำหนดประเภทข้อมูลด้วย

1

อย่าสับสนแบบไดนามิกและ var การประกาศตัวแปรโลคัลโดยใช้ var เป็นเพียงช็อตคัตเชิงไวยากรณ์ที่คอมไพเลอร์อนุมานชนิดข้อมูลเฉพาะจากนิพจน์ คีย์เวิร์ด var สามารถใช้สำหรับการประกาศตัวแปรโลคัลภายในเมธอดขณะที่คีย์เวิร์ดแบบไดนามิกสามารถใช้สำหรับตัวแปรโลคัลฟิลด์และอาร์กิวเมนต์ คุณไม่สามารถส่งนิพจน์เป็น var แต่คุณสามารถใช้นิพจน์เป็นแบบไดนามิกได้ คุณต้องเตรียมใช้งานตัวแปรที่ประกาศอย่างชัดเจนโดยใช้ var ในขณะที่คุณไม่จำเป็นต้องเตรียมใช้งานตัวแปรที่ประกาศด้วยไดนามิก


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 ด้วย แต่ก็ไม่ให้การสนับสนุนที่ดีกว่าเมื่อเราให้ลินุกซ์ด้วยเพราะมันไม่รองรับการแสดงออกแลมบ์ดาวิธีการขยายและวิธีการไม่ระบุชื่อ


1

นี่คือความแตกต่าง

  • var ถูกพิมพ์แบบคงที่ (เวลารวบรวม) แบบไดนามิกถูกพิมพ์แบบไดนามิก (เวลาทำงาน)

  • ตัวแปรที่ประกาศเป็น var สามารถใช้ได้ภายในเครื่องเท่านั้นตัวแปรแบบไดนามิกสามารถส่งผ่านเป็น params ไปยังฟังก์ชัน (ฟังก์ชันลายเซ็นสามารถกำหนดพารามิเตอร์เป็นแบบไดนามิก แต่ไม่ใช่ var)

  • ด้วยความละเอียดของคุณสมบัติแบบไดนามิกที่เกิดขึ้นที่รันไทม์และนั่นไม่ใช่กรณีที่มี var ซึ่งหมายความว่าในเวลารวบรวมตัวแปรใด ๆ ที่ประกาศเป็นแบบไดนามิกสามารถเรียกวิธีการที่อาจหรืออาจไม่มีอยู่และดังนั้นคอมไพเลอร์จะไม่โยนข้อผิดพลาด

  • การพิมพ์ที่มี var ไม่สามารถทำได้ แต่ด้วยการเคลื่อนไหวที่เป็นไปได้ (คุณสามารถส่งวัตถุเป็นแบบไดนามิก แต่ไม่เป็น var)

อรุณวิชัยวรวรรณ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.