Sự khác biệt giữa động (C # 4) và var là gì?


199

Tôi đã đọc rất nhiều bài viết về từ khóa mới được gửi với C # v4, nhưng tôi không thể tìm ra sự khác biệt giữa "động" và "var".

Bài viết này khiến tôi suy nghĩ về nó, nhưng tôi vẫn không thể thấy bất kỳ sự khác biệt.

Có phải bạn chỉ có thể sử dụng "var" như một biến cục bộ, nhưng động như cả cục bộ và toàn cầu?

Bạn có thể hiển thị một số mã mà không có từ khóa động và sau đó hiển thị cùng mã với từ khóa động?

Câu trả lời:


455

varđược gõ tĩnh - trình biên dịch và thời gian chạy biết loại - chúng chỉ giúp bạn tiết kiệm một số thao tác gõ ... sau đây giống hệt 100%:

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

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

Tất cả những gì đã xảy ra là trình biên dịch đã tìm ra đó sphải là một chuỗi (từ trình khởi tạo). Trong cả hai trường hợp, nó biết (trong IL) s.Lengthcó nghĩa là thuộc tính (thể hiện) string.Length.

dynamiclà một con thú rất khác nhau; nó tương tự nhất object, nhưng với công văn động:

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

Ở đây, sđược đánh máy là năng động . Nó không biết về string.Lengthnó, bởi vì nó không biết về sthời gian biên dịch. Ví dụ, sau đây cũng sẽ biên dịch (nhưng không chạy):

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

Trong thời gian chạy (chỉ), nó sẽ kiểm tra thuộc FlibbleBananaSnowballtính - không tìm thấy nó và phát nổ trong một cơn mưa tia lửa.

Với dynamic, các thuộc tính / phương thức / toán tử / vv được giải quyết trong thời gian chạy , dựa trên đối tượng thực tế. Rất thuận tiện để nói chuyện với COM (có thể có các thuộc tính chỉ dành cho thời gian chạy), DLR hoặc các hệ thống động khác, như thế nào javascript.


3
Một câu hỏi thú vị sẽ là nếu có tổ tiên động của các lớp được khai báo tĩnh. Ví dụ: class X {public int Y {get; set;}} Dynamic (X) s = GetecialX (); Gọi kiểm tra chuỗi = sY; sẽ tạo ra lỗi trình biên dịch vì trình biên dịch biết về Y nhưng chuỗi test2 = sZ sẽ biên dịch tốt và được kiểm tra trong thời gian chạy. Tôi có thể nghĩ về nhiều giá trị của các lớp nửa năng động như vậy!
mmmmmmmm

@rstevens - IIRC, bạn có thể thêm hành vi động thông qua giao diện (mặc dù không có hỗ trợ ngôn ngữ trực tiếp để triển khai các loại động trong C # - chỉ tiêu thụ chúng), vì vậy điều này không thực tế ... ôi thật thú vị chúng ta có thể có; - p
Marc Gravell

Mặc dù điều quan trọng cần lưu ý là đôi khi varcó thể suy ra các loại có thể không mong muốn do các kiểu con và phôi ẩn. Đó là, varcó thể đã giải quyết một loại khác biệt tĩnh so với dự kiến ​​khi các diễn biến ngầm xảy ra (đáng chú ý nhất là một loại tổng quát hơn, nhưng nó không giới hạn ở điều này). Một ví dụ tầm thường là object x = ""so với so var x = ""với var x = "" as object, nhưng các trường hợp lén lút (và thực tế) khác có thể xảy ra và có thể gây ra các lỗi tinh vi.

Để giải thích rõ hơn về ví dụ hay của Marc, trong trường hợp đầu tiên (với kiểu tĩnh), trình biên dịch biết chính xác trong số nhiều tình trạng quá tảiWriteLine cần gọi. "Ràng buộc" này xảy ra thời gian biên dịch. Trong trường hợp với dynamic, loại .Lengthphải dynamicquá, và phải đến thời gian chạy mới quyết định mức quá tải nào (nếu có) WriteLinephù hợp nhất. Binding xảy ra thời gian chạy.
Jeppe Stig Nielsen

4
Khi bạn di chuột vartừ khóa trong Visual Studio, loại thực tế được hiển thị đang được suy luận. Cho bạn thấy rằng loại được biết tại thời gian biên dịch.
Christian Fredh

56

Các biến được khai báo với var được nhập ngầm nhưng đượctĩnh . Các biến được khai báo với động được gõ động. Khả năng này đã được thêm vào CLR để hỗ trợ các ngôn ngữ động như Ruby và Python.

Tôi nên thêm rằng điều này có nghĩa là các khai báo động được giải quyết tại thời gian chạy, khai báo var được giải quyết tại thời gian biên dịch.


42

Tôi sẽ giải thích sự khác biệt giữa độngvar .

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

Điều này sẽ làm việc. trình biên dịch có thể tạo lại kiểu biến động .
đầu tiên nó tạo kiểu dưới dạng số nguyên và sau đó trình biên dịch sẽ tạo lại kiểu dưới dạng chuỗi
nhưng trong trường hợp 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 


Khi sử dụng từ khóa ' var ', loại được trình biên dịch quyết định tại thời điểm biên dịch, trong khi khi sử dụng từ khóa ' động ', loại được quyết định bởi thời gian chạy.
' Var ' từ khóa, một biến địa phương mạnh mẽ ngầm gõ mà trình biên dịch có thể xác định loại từ biểu thức khởi tạo - rất hữu ích khi thực hiện chương trình LINQ.
Trình biên dịch không có bất kỳ thông tin về động kiểu của biến. vì vậy trình biên dịch sẽ không hiển thị bất kỳ thông minh.
trình biên dịch có tất cả thông tin về giá trị được lưu trữ của kiểu var để trình biên dịch sẽ hiển thị thông minh.
kiểu động có thể được truyền dưới dạng đối số hàm và hàm cũng có thể trả về kiểu đối tượng
Nhưng kiểu
var không thể được truyền dưới dạng đối số hàm và hàm không thể trả về kiểu đối tượng. Loại biến này có thể làm việc trong phạm vi mà nó xác định.


14

var ngụ ý rằng kiểm tra kiểu tĩnh (liên kết sớm) được áp dụng. động ngụ ý rằng kiểm tra loại động (ràng buộc muộn) được áp dụng. Về mặt mã, hãy bỏ qua những điều sau đây:

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

Nếu bạn biên dịch cái này và kiểm tra kết quả với ILSpy, bạn sẽ thấy rằng trình biên dịch đã thêm một số mã ràng buộc muộn sẽ xử lý cuộc gọi đến Hello () từ b, trong khi ràng buộc sớm được áp dụng cho a, a có thể gọi Hello () trực tiếp.

ví dụ: (tháo gỡ 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);
        }
    }
}

Điều tốt nhất bạn có thể làm để khám phá sự khác biệt là viết cho mình một ứng dụng bảng điều khiển nhỏ như ứng dụng này và tự kiểm tra nó với ILSpy.


ví dụ cơ bản tuyệt vời về cách IL đối xử với cả hai sau khi biên dịch. Cảm ơn.
Các vị vua

12

Một sự khác biệt lớn - bạn có thể có một kiểu trả về động.

dynamic Foo(int x)
{
    dynamic result;

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

    return result;
}

10

Dưới đây là ví dụ đơn giản thể hiện sự khác biệt giữa Dynamic (4.0) và 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
Ấn tượng của tôi là sự hiện diện của các **ký tự trong ví dụ mã chỉ nhằm mục đích chỉ nhấn mạnh và không nhằm mục đích là một phần của mã làm việc thực sự.
DavidRR

7

var chỉ là một tốc ký cho một khai báo kiểu thông thường, trong đó bạn để trình biên dịch đoán đúng loại.

dynamic là một loại (tĩnh) mới, trong đó tất cả các kiểm tra được thực hiện trong thời gian chạy, không phải bởi trình biên dịch.


4

Kiểu của một biến được khai báo với var được xác định bởi trình biên dịch, nó là một phím tắt để chỉ định tên của loại, không có gì hơn.

Tuy nhiên, động được xác định trong thời gian chạy, trình biên dịch không có ý tưởng về loại thực tế và tất cả các truy cập phương thức / trường / thuộc tính với biến đó sẽ được xử lý khi chạy.


3

Đây là một video youtube tuyệt vời nói về varVS Dynamicvới trình diễn thực tế.

Dưới đây là một lời giải thích chi tiết hơn với ảnh chụp nhanh.

Var được liên kết sớm (kiểm tra tĩnh) trong khi động bị ràng buộc muộn (đánh giá động).

Từ khóa Var nhìn vào dữ liệu phía bên tay phải của bạn và sau đó trong thời gian biên dịch, nó quyết định kiểu dữ liệu bên trái. Nói cách khác, từ khóa var chỉ giúp bạn nhập nhiều thứ. Hãy nhìn vào hình ảnh dưới đây khi chúng tôi đã cung cấp dữ liệu chuỗi và biến x hiển thị loại dữ liệu chuỗi trong mẹo công cụ của tôi.

nhập mô tả hình ảnh ở đây

Mặt khác, từ khóa động là dành cho mục đích hoàn toàn khác. Các đối tượng động được đánh giá trong thời gian chạy. Ví dụ trong đoạn mã dưới đây, thuộc tính "Độ dài" có tồn tại hay không được đánh giá trong thời gian chạy. Tôi đã cố tình gõ một chữ "l" nhỏ, vì vậy chương trình này đã biên dịch tốt nhưng khi nó thực sự thực hiện thì nó đã xuất hiện lỗi khi thuộc tính "độ dài" đã được gọi (NHỎ "l").

nhập mô tả hình ảnh ở đây


2

cả biến động và biến var đều có thể lưu trữ bất kỳ loại giá trị nào nhưng yêu cầu của nó để khởi tạo 'var' tại thời điểm khai báo.

Trình biên dịch không có bất kỳ thông tin nào về loại biến 'động'. var là trình biên dịch an toàn, tức là trình biên dịch có tất cả thông tin về giá trị được lưu trữ, do đó nó không gây ra bất kỳ vấn đề nào trong thời gian chạy.

Kiểu động có thể được truyền dưới dạng đối số hàm và hàm cũng có thể trả về nó. Kiểu Var không thể được truyền dưới dạng đối số hàm và hàm không thể trả về kiểu đối tượng. Loại biến này có thể làm việc trong phạm vi mà nó xác định.

Trong trường hợp Casting động không bắt buộc nhưng bạn cần biết thuộc tính và phương thức liên quan đến kiểu được lưu trữ, trong khi đối với var Không cần truyền vì trình biên dịch có tất cả thông tin để thực hiện thao tác.

động: Hữu ích khi mã hóa bằng cách sử dụng sự phản chiếu hoặc hỗ trợ ngôn ngữ động hoặc với các đối tượng COM, bởi vì chúng tôi yêu cầu viết số lượng mã ít hơn.

var: Hữu ích khi nhận kết quả từ các truy vấn linq. Trong khung 3.5, nó giới thiệu để hỗ trợ tính năng linq.

Tham khảo: Counsellingbyabhi


2
  1. Var và kiểu xác định động.
  2. var tại thời gian biên dịch trong khi động đang ở thời gian chạy.
  3. trong khai báo var và khởi tạo cả hai đều bắt buộc giống như biến không đổi trong khi
  4. trong khởi tạo động có thể có thời gian chạy như các biến chỉ đọc.
  5. trong loại var, bất kỳ loại nào được quyết định tại thời điểm khởi tạo không thể thay đổi tiếp theo nhưng
  6. động có thể áp dụng bất kỳ loại nào ngay cả người dùng xác định kiểu dữ liệu cũng.

1

Đừng nhầm lẫn giữa động và var. Khai báo một biến cục bộ bằng var chỉ là một phím tắt cú pháp có trình biên dịch suy ra kiểu dữ liệu cụ thể từ một biểu thức. Từ khóa var chỉ có thể được sử dụng để khai báo các biến cục bộ bên trong một phương thức trong khi từ khóa động có thể được sử dụng cho các biến, trường và đối số cục bộ. Bạn không thể truyền biểu thức thành var, nhưng bạn có thể chuyển biểu thức thành động. Bạn phải khởi tạo một cách rõ ràng một biến được khai báo bằng var trong khi bạn không phải khởi tạo một biến được khai báo bằng động.


1
  1. Từ khóa Var (ngầm định gõ biến cục bộ) được sử dụng để xác định biến cục bộ. Trong trường hợp của Var, kiểu dữ liệu cơ bản được xác định tại thời điểm biên dịch dựa trên phép gán ban đầu. Sau đó, phép gán ban đầu đã được thực hiện với loại Var, sau đó sẽ trở nên gõ mạnh. Nếu bạn cố lưu trữ bất kỳ giá trị không tương thích nào với loại Var, nó sẽ dẫn đến lỗi thời gian biên dịch.

Thí dụ:

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.

Nhưng trong Kiểu động, loại cơ bản chỉ được xác định khi chạy. Kiểu dữ liệu không được kiểm tra tại thời gian biên dịch và nó cũng không được gõ mạnh. Chúng tôi có thể gán bất kỳ giá trị ban đầu nào cho loại động và sau đó có thể gán lại cho bất kỳ giá trị mới nào giá trị trong suốt cuộc đời của nó.

Thí dụ:

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]

Nó cũng không cung cấp hỗ trợ IntelliSense. Nó cũng không hỗ trợ tốt hơn khi chúng tôi cũng làm việc với linq. Bởi vì nó không hỗ trợ các biểu thức lambda, phương thức mở rộng và phương thức ẩn danh.


1

Dưới đây là sự khác biệt

  • var được gõ tĩnh (thời gian biên dịch), động được gõ động (thời gian chạy)

  • Một biến được khai báo là var chỉ có thể được sử dụng cục bộ, các biến động có thể được truyền vào dưới dạng params cho hàm (chữ ký hàm có thể định nghĩa một param là động nhưng không phải var).

  • với độ phân giải của các thuộc tính xảy ra trong thời gian chạy và đó không phải là trường hợp với var có nghĩa là tại thời điểm biên dịch, bất kỳ biến nào được khai báo là động có thể gọi một phương thức có thể tồn tại hoặc có thể không tồn tại và do đó trình biên dịch sẽ không đưa ra lỗi.

  • Loại truyền với var không thể nhưng với động thì có thể (bạn có thể truyền đối tượng là động nhưng không phải là var).

Arun Vijayraghavan

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.