Loại 'động' trong C # 4.0 được sử dụng để làm gì?


236

C # 4.0 đã giới thiệu một loại mới gọi là 'động'. Tất cả nghe có vẻ tốt, nhưng một lập trình viên sẽ sử dụng nó để làm gì?

Có một tình huống mà nó có thể tiết kiệm trong ngày?



Nó hữu ích khi làm việc với COM hoặc các ngôn ngữ được gõ động. Ví dụ: nếu bạn sử dụng lua hoặc python để tạo kịch bản cho ngôn ngữ của mình, sẽ rất thuận tiện khi chỉ cần gọi vào mã script như thể đó là mã thông thường.
CodeInChaos


Tôi hy vọng bài viết này có câu trả lời đầy đủ cho câu hỏi của bạn visualstudiomagazine.com/Articles/2011/02/01/iêu
Nhà phát triển

Câu trả lời:


196

Từ khóa động mới đối với C # 4.0 và được sử dụng để báo cho trình biên dịch rằng loại của biến có thể thay đổi hoặc không được biết cho đến khi chạy. Hãy nghĩ về nó như có thể tương tác với một đối tượng mà không cần phải sử dụng nó.

dynamic cust = GetCustomer();
cust.FirstName = "foo"; // works as expected
cust.Process(); // works as expected
cust.MissingMethod(); // No method found!

Lưu ý rằng chúng tôi không cần bỏ cũng như tuyên bố quyền giám hộ là loại Khách hàng. Bởi vì chúng tôi đã khai báo nó động, thời gian chạy tiếp quản và sau đó tìm kiếm và đặt thuộc tính FirstName cho chúng tôi. Bây giờ, tất nhiên, khi bạn đang sử dụng một biến động, bạn đang từ bỏ việc kiểm tra loại trình biên dịch. Điều này có nghĩa là lệnh gọi.MissingMethod () sẽ biên dịch và không thất bại cho đến khi thực thi. Kết quả của hoạt động này là RuntimeBinderException vì MissingMethod không được xác định trên lớp Khách hàng.

Ví dụ trên cho thấy cách hoạt động năng động khi gọi các phương thức và thuộc tính. Một tính năng mạnh mẽ (và có khả năng nguy hiểm) khác là có thể sử dụng lại các biến cho các loại dữ liệu khác nhau. Tôi chắc rằng các lập trình viên Python, Ruby và Perl ngoài kia có thể nghĩ ra hàng triệu cách để tận dụng lợi thế này, nhưng tôi đã sử dụng C # lâu đến nỗi nó chỉ cảm thấy "sai" với tôi.

dynamic foo = 123;
foo = "bar";

OK, vì vậy rất có thể bạn sẽ không viết mã như trên rất thường xuyên. Tuy nhiên, có thể đôi khi, việc tái sử dụng biến có thể có ích hoặc dọn sạch một đoạn mã kế thừa bẩn. Một trường hợp đơn giản tôi gặp phải thường xuyên là phải liên tục giữa thập phân và gấp đôi.

decimal foo = GetDecimalValue();
foo = foo / 2.5; // Does not compile
foo = Math.Sqrt(foo); // Does not compile
string bar = foo.ToString("c");

Dòng thứ hai không biên dịch vì 2.5 được gõ dưới dạng gấp đôi và dòng 3 không biên dịch vì Math.Sqrt mong đợi gấp đôi. Rõ ràng, tất cả những gì bạn phải làm là bỏ và / hoặc thay đổi loại biến của bạn, nhưng có thể có những tình huống mà động có ý nghĩa để sử dụng.

dynamic foo = GetDecimalValue(); // still returns a decimal
foo = foo / 2.5; // The runtime takes care of this for us
foo = Math.Sqrt(foo); // Again, the DLR works its magic
string bar = foo.ToString("c");

Đọc thêm tính năng: http://www.codeproject.com/KB/cs/CSharp4Features.aspx


96
Cá nhân tôi không thích suy nghĩ sử dụng dynamicc # để giải quyết các vấn đề có thể giải quyết (thậm chí tốt hơn) bằng các tính năng c # tiêu chuẩn và gõ tĩnh, hoặc nhiều nhất là với suy luận kiểu ( var). chỉdynamic nên được sử dụng khi có vấn đề về khả năng tương tác với DLR. Nếu bạn viết mã bằng ngôn ngữ gõ tĩnh, như c #, thì hãy thực hiện và không mô phỏng ngôn ngữ động. Đó chỉ là xấu xí.
Philip Daubmeier

40
Nếu bạn sử dụng nhiều dynamicbiến trong mã của mình, nơi bạn không cần đến chúng (như trong ví dụ của bạn với squareroot), bạn sẽ từ bỏ việc kiểm tra lỗi thời gian biên dịch sạch; thay vào đó bạn đang nhận được lỗi thời gian chạy có thể.
Philip Daubmeier

33
Chủ yếu là tốt, nhưng một vài lỗi nhỏ. Đầu tiên, không đúng khi nói rằng động có nghĩa là loại biến có thể thay đổi. Biến trong câu hỏi thuộc loại "động" (theo quan điểm của ngôn ngữ C #; từ phối cảnh của CLR, biến là của đối tượng loại). Loại của một biến không bao giờ thay đổi. Kiểu thời gian chạy của giá trị của một biến có thể là bất kỳ loại nào tương thích với loại biến. (Hoặc trong trường hợp loại tham chiếu, nó có thể là null.)
Eric Lippert

15
Về điểm thứ hai của bạn: C # đã có tính năng "tạo một biến bạn có thể đặt bất cứ thứ gì vào" - bạn luôn có thể tạo một biến của loại đối tượng. Điều thú vị về động là những gì bạn chỉ ra trong đoạn đầu tiên của mình: động giống hệt đối tượng, ngoại trừ việc phân tích ngữ nghĩa được hoãn lại cho đến khi chạy và phân tích ngữ nghĩa được thực hiện trên kiểu thời gian chạy của biểu thức. (Chủ yếu. Có một số trường hợp ngoại lệ.)
Eric Lippert

18
Tôi đã dành một điểm hạ gục về điều này, chủ yếu bởi vì nó hoàn toàn ủng hộ việc sử dụng từ khóa để sử dụng chung. Nó có một mục đích được nhắm mục tiêu cụ thể (được mô tả hoàn hảo trong câu trả lời của Lasses) và mặc dù câu trả lời này là đúng về mặt kỹ thuật, nó có khả năng khiến các nhà phát triển lạc lối.
Eight-Bit

211

Các dynamictừ khóa được thêm vào, cùng với nhiều tính năng mới khác của C # 4.0, để làm cho nó đơn giản để nói chuyện với mã mà cuộc sống trong hoặc xuất phát từ runtimes khác, có các API khác nhau.

Lấy một ví dụ.

Nếu bạn có một đối tượng COM, như Word.Applicationđối tượng và muốn mở một tài liệu, phương thức để thực hiện đi kèm với không dưới 15 tham số, hầu hết trong số đó là tùy chọn.

Để gọi phương thức này, bạn sẽ cần một cái gì đó như thế này (tôi đang đơn giản hóa, đây không phải là mã thực tế):

object missing = System.Reflection.Missing.Value;
object fileName = "C:\\test.docx";
object readOnly = true;
wordApplication.Documents.Open(ref fileName, ref missing, ref readOnly,
    ref missing, ref missing, ref missing, ref missing, ref missing,
    ref missing, ref missing, ref missing, ref missing, ref missing,
    ref missing, ref missing);

Lưu ý tất cả những lập luận đó? Bạn cần vượt qua những người kể từ C # trước phiên bản 4.0 không có khái niệm về các đối số tùy chọn. Trong C # 4.0, API COM đã được làm việc dễ dàng hơn bằng cách giới thiệu:

  1. Đối số tùy chọn
  2. Tạo reftùy chọn cho API COM
  3. Đối số được đặt tên

Cú pháp mới cho cuộc gọi trên sẽ là:

wordApplication.Documents.Open(@"C:\Test.docx", ReadOnly: true);

Xem nó trông dễ dàng hơn bao nhiêu, nó trở nên dễ đọc hơn bao nhiêu?

Chúng ta hãy phá vỡ điều đó:

                                    named argument, can skip the rest
                                                   |
                                                   v
wordApplication.Documents.Open(@"C:\Test.docx", ReadOnly: true);
                                 ^                         ^
                                 |                         |
                               notice no ref keyword, can pass
                               actual parameter values instead

Điều kỳ diệu là trình biên dịch C # bây giờ sẽ tiêm mã cần thiết và làm việc với các lớp mới trong thời gian chạy, để thực hiện gần như chính xác những gì bạn đã làm trước đây, nhưng cú pháp đã bị ẩn khỏi bạn, bây giờ bạn có thể tập trung vào những gì , và không quá nhiều về làm thế nào . Anders Hejlsberg thích nói rằng bạn phải thực hiện các "câu thần chú" khác nhau, đó là một kiểu chơi chữ cho phép thuật của toàn bộ, trong đó bạn thường phải vẫy tay và nói một số từ ma thuật theo đúng thứ tự để có được một loại phép thuật nhất định đi. Cách nói chuyện API cũ với các đối tượng COM là rất nhiều, bạn cần phải vượt qua rất nhiều vòng để dỗ trình biên dịch biên dịch mã cho bạn.

Mọi thứ bị phá vỡ trong C # trước phiên bản 4.0 thậm chí nhiều hơn nếu bạn cố gắng nói chuyện với một đối tượng COM mà bạn không có giao diện hoặc lớp, tất cả những gì bạn có là một IDispatchtài liệu tham khảo.

Nếu bạn không biết nó là gì, IDispatchvề cơ bản là sự phản chiếu cho các đối tượng COM. Với một IDispatchgiao diện, bạn có thể hỏi đối tượng "số id cho phương thức được gọi là Save" là gì và xây dựng các mảng của một loại nhất định có chứa các giá trị đối số và cuối cùng gọi một Invokephương thức trên IDispatchgiao diện để gọi phương thức, truyền tất cả thông tin bạn đã quản lý để cùng nhau tranh giành.

Phương thức Save ở trên có thể trông như thế này (đây chắc chắn không phải là mã đúng):

string[] methodNames = new[] { "Open" };
Guid IID = ...
int methodId = wordApplication.GetIDsOfNames(IID, methodNames, methodNames.Length, lcid, dispid);
SafeArray args = new SafeArray(new[] { fileName, missing, missing, .... });
wordApplication.Invoke(methodId, ... args, ...);

Tất cả điều này chỉ để mở một tài liệu.

VB đã có các đối số tùy chọn và hỗ trợ cho hầu hết những điều này từ lâu, vì vậy mã C # này:

wordApplication.Documents.Open(@"C:\Test.docx", ReadOnly: true);

về cơ bản chỉ là C # bắt kịp VB về tính biểu cảm, nhưng thực hiện nó đúng cách, bằng cách làm cho nó có thể mở rộng và không chỉ cho COM. Tất nhiên điều này cũng có sẵn cho VB.NET hoặc bất kỳ ngôn ngữ nào khác được xây dựng trên đầu thời gian chạy .NET.

Bạn có thể tìm thêm thông tin về IDispatchgiao diện trên Wikipedia: IDispatch nếu bạn muốn đọc thêm về nó. Nó thực sự là thứ linh tinh.

Tuy nhiên, nếu bạn muốn nói chuyện với một đối tượng Python thì sao? Có một API khác với API được sử dụng cho các đối tượng COM và vì các đối tượng Python cũng có tính chất động, bạn cần phải sử dụng phép thuật phản chiếu để tìm đúng phương thức để gọi, tham số của chúng, v.v. nhưng không phải là .NET Sự phản chiếu, một cái gì đó được viết cho Python, khá giống mã IDispatch ở trên, hoàn toàn khác nhau.

Và đối với Ruby? Một API khác vẫn còn.

JavaScript? Cùng một giao dịch, API khác nhau cho điều đó là tốt.

Từ khóa động bao gồm hai điều:

  1. Từ khóa mới trong C #, dynamic
  2. Một tập hợp các lớp thời gian chạy biết cách xử lý các loại đối tượng khác nhau, thực hiện một API cụ thể mà dynamictừ khóa yêu cầu và ánh xạ các cuộc gọi đến đúng cách thực hiện. API thậm chí còn được ghi lại, vì vậy nếu bạn có các đối tượng xuất phát từ thời gian chạy không được bảo hiểm, bạn có thể thêm nó.

Các dynamictừ khóa được không, tuy nhiên, có nghĩa là để thay thế bất kỳ mã .NET chỉ đang tồn tại. Chắc chắn, bạn có thể làm điều đó, nhưng nó không được thêm vào vì lý do đó, và các tác giả của ngôn ngữ lập trình C # với Anders Hejlsberg ở phía trước, đã kiên quyết nhất rằng họ vẫn coi C # là ngôn ngữ được đánh máy mạnh mẽ và sẽ không hy sinh nguyên tắc đó.

Điều này có nghĩa là mặc dù bạn có thể viết mã như thế này:

dynamic x = 10;
dynamic y = 3.14;
dynamic z = "test";
dynamic k = true;
dynamic l = x + y * z - k;

và có nó biên dịch, nó không có nghĩa là một loại hệ thống ma thuật cho phép-tìm-ra-những gì bạn có nghĩa là trong thời gian chạy.

Toàn bộ mục đích là để làm cho việc nói chuyện với các loại đối tượng khác dễ dàng hơn.

Có rất nhiều tài liệu trên internet về từ khóa, người đề xướng, người phản đối, thảo luận, tán tỉnh, khen ngợi, v.v.

Tôi khuyên bạn nên bắt đầu với các liên kết sau và sau đó google để biết thêm:


12
Nó cũng hữu ích ngoài COM cho API API web nơi cấu trúc của các đối tượng JSON được tuần tự hóa không được chỉ định trong C #. Ví dụ: Phương thức Giải mã của System.Web.Helpers.Json trả về một đối tượng động .
dumbledad

Một khía cạnh khác về "họ vẫn coi C # là một ngôn ngữ được gõ mạnh": Eric Lippert không phải là một người hâm mộ của "gõ mạnh" như một mô tả.
Andrew Keeton

Tôi không đồng ý với anh ta, nhưng đó là vấn đề quan điểm, không phải là vấn đề thực tế. Đối với tôi "gõ mạnh" có nghĩa là trình biên dịch biết, tại thời điểm biên dịch, loại nào được sử dụng và do đó thực thi các quy tắc được đặt xung quanh các loại đó. Thực tế là bạn có thể chọn loại động mà trì hoãn việc kiểm tra quy tắc và ràng buộc với thời gian chạy, đối với tôi, điều đó không có nghĩa là ngôn ngữ được gõ yếu. Tôi thường không tương phản gõ mạnh vào gõ yếu, tuy nhiên, tôi thường so sánh nó với gõ động, như các ngôn ngữ như Python, nơi mọi thứ đều là con vịt cho đến khi nó sủa.
Lasse V. Karlsen

Điểm của câu trả lời này là gì? Một nửa trong số đó là về các tham số tùy chọn và giao diện IDispatch.
Xam

Đó là lý do tại sao dynamicđã được thêm vào, để hỗ trợ các hệ sinh thái khác về cách gọi phương thức giống như phản xạ có thể được thực hiện, cũng như cung cấp một cách tiếp cận hộp đen cho các cấu trúc dữ liệu với cách thức được chứng minh bằng tài liệu này.
Lasse V. Karlsen

29

Tôi ngạc nhiên rằng không ai đề cập đến nhiều công văn . Cách thông thường để giải quyết vấn đề này là thông qua mẫu Khách truy cập và điều đó không phải lúc nào cũng có thể để bạn kết thúc với các iskiểm tra xếp chồng .

Vì vậy, đây là một ví dụ thực tế của một ứng dụng của riêng tôi. Thay vì làm:

public static MapDtoBase CreateDto(ChartItem item)
{
    if (item is ElevationPoint) return CreateDtoImpl((ElevationPoint)item);
    if (item is MapPoint) return CreateDtoImpl((MapPoint)item);
    if (item is MapPolyline) return CreateDtoImpl((MapPolyline)item);
    //other subtypes follow
    throw new ObjectNotFoundException("Counld not find suitable DTO for " + item.GetType());
}

Bạn làm:

public static MapDtoBase CreateDto(ChartItem item)
{
    return CreateDtoImpl(item as dynamic);
}

private static MapDtoBase CreateDtoImpl(ChartItem item)
{
    throw new ObjectNotFoundException("Counld not find suitable DTO for " + item.GetType());
}

private static MapDtoBase CreateDtoImpl(MapPoint item)
{
    return new MapPointDto(item);
}

private static MapDtoBase CreateDtoImpl(ElevationPoint item)
{
    return new ElevationDto(item);
}

Lưu ý rằng trong trường hợp đầu tiên ElevationPointlà lớp con của MapPointvà nếu nó không được đặt trước MapPoint thì nó sẽ không bao giờ đạt được. Đây không phải là trường hợp động, vì phương thức khớp gần nhất sẽ được gọi.

Như bạn có thể đoán từ mã, tính năng đó trở nên tiện dụng trong khi tôi đang thực hiện dịch từ các đối tượng ChartItem sang các phiên bản tuần tự hóa của chúng. Tôi không muốn làm ô nhiễm mã của mình với khách truy cập và tôi cũng không muốn làm ô nhiễm ChartItemcác đối tượng của mình với các thuộc tính cụ thể tuần tự hóa vô dụng.


Không biết về trường hợp sử dụng này. Một chút hacky tốt nhất, mặc dù. Nó sẽ ném bất kỳ máy phân tích tĩnh nào.
Kugel

2
@Kugel đó là sự thật, nhưng tôi sẽ không gọi đó là hack . Phân tích tĩnh là tốt, nhưng tôi sẽ không để nó ngăn tôi khỏi một giải pháp tao nhã, trong đó các giải pháp thay thế là: vi phạm nguyên tắc đóng mở (mẫu khách truy cập) hoặc tăng độ phức tạp theo chu kỳ với ischồng lên nhau.
Stelios Adamantidis

4
Vâng, bạn có tùy chọn khớp mẫu với C # 7 không?
Kugel

2
Theo cách đó, các toán tử ít tốn kém hơn rất nhiều (tránh sử dụng hai lần) và bạn sẽ lấy lại phân tích tĩnh ;-) và hiệu suất.
Kugel

@idbrii xin đừng thay đổi câu trả lời của tôi. Vui lòng gửi bình luận và tôi sẽ làm rõ (nếu cần) vì tôi vẫn hoạt động trong cộng đồng này. Ngoài ra, xin vui lòng không sử dụng magic; không có thứ gọi là ma thuật
Stelios Adamantidis

11

Nó giúp các ngôn ngữ gõ tĩnh (CLR) dễ dàng tương tác với các ngôn ngữ động (python, ruby ​​...) chạy trên DLR (thời gian chạy ngôn ngữ động), xem MSDN :

Ví dụ: bạn có thể sử dụng đoạn mã sau để tăng bộ đếm trong XML bằng C #.

Scriptobj.SetProperty("Count", ((int)GetProperty("Count")) + 1);

Bằng cách sử dụng DLR, bạn có thể sử dụng mã sau đây cho cùng một hoạt động.

scriptobj.Count += 1;

MSDN liệt kê những ưu điểm này:

  • Đơn giản hóa việc chuyển ngôn ngữ động sang .NET Framework
  • Cho phép các tính năng động trong các ngôn ngữ được nhập tĩnh
  • Cung cấp các lợi ích trong tương lai của DLR và .NET Framework
  • Cho phép chia sẻ thư viện và đối tượng
  • Cung cấp công văn và yêu cầu nhanh

Xem MSDN để biết thêm chi tiết.


1
Và sự thay đổi mà ông VM yêu cầu đối với động thực sự giúp ngôn ngữ động dễ dàng hơn.
Dykam

2
@Dykam: Không có thay đổi đối với VM. DLR hoạt động tốt hoàn toàn trở lại .NET 2.0.
Jörg W Mittag

@ Jörg, vâng, có một sự thay đổi. DLR được viết lại một phần bởi vì bây giờ VM đã tích hợp để hỗ trợ cho độ phân giải động.
Dykam

Tôi đã hơi quá lạc quan, nghiên cứu cho thấy những thay đổi không lớn.
Dykam

4

Một ví dụ về sử dụng:

Bạn tiêu thụ nhiều lớp có thuộc tính chung 'CreationDate':

public class Contact
{
    // some properties

    public DateTime CreationDate { get; set; }        
}

public class Company
{
    // some properties

    public DateTime CreationDate { get; set; }

}

public class Opportunity
{
    // some properties

    public DateTime CreationDate { get; set; }

}

Nếu bạn viết một phương thức cộng đồng lấy giá trị của Thuộc tính 'CreationDate', bạn phải sử dụng sự phản chiếu:

    static DateTime RetrieveValueOfCreationDate(Object item)
    {
        return (DateTime)item.GetType().GetProperty("CreationDate").GetValue(item);
    }

Với khái niệm 'động', mã của bạn thanh lịch hơn nhiều:

    static DateTime RetrieveValueOfCreationDate(dynamic item)
    {
        return item.CreationDate;
    }

7
Vịt gõ, đẹp. Tuy nhiên, bạn nên sử dụng một giao diện cho việc này nếu đó là những kiểu của bạn.
Kugel

3

COM xen kẽ. Đặc biệt là IUn Unknown. Nó được thiết kế đặc biệt cho nó.


2

Nó chủ yếu sẽ được sử dụng bởi các nạn nhân RAD và Python để phá hủy chất lượng mã, IntelliSense và biên dịch phát hiện lỗi thời gian.


Một câu trả lời cay độc nhưng dễ dàng quá đúng. Tôi đã thấy nó được thực hiện đơn giản để tránh việc khai báo các cấu trúc với kết quả là mã hoạt động tốt, nhưng thổi bay ngăn xếp của nó theo những cách không thể đoán trước ngay khi bạn di chuyển phô mai.
AnthonyVO

Vâng, bạn sẽ thấy rằng góc cắt cổ điển với rất nhiều tính năng ngôn ngữ khác. Không có gì ngạc nhiên khi bạn cũng thấy nó ở đây.
Hawkeye4040

1

Nó đánh giá trong thời gian chạy, vì vậy bạn có thể chuyển loại như bạn có thể trong JavaScript sang bất cứ thứ gì bạn muốn. Điều này hợp pháp:

dynamic i = 12;
i = "text";

Và vì vậy bạn có thể thay đổi loại khi bạn cần. Sử dụng nó như là một phương sách cuối cùng; nó có lợi, nhưng tôi nghe nói rất nhiều điều xảy ra trong bối cảnh IL được tạo ra và điều đó có thể có giá thực hiện.


7
Tôi sẽ do dự khi nói rằng đó là "hợp pháp". Nó chắc chắn sẽ biên dịch, vì vậy nó là "mã hợp pháp" theo nghĩa là trình biên dịch sẽ biên dịch nó và bộ thực thi sẽ chạy nó. Nhưng tôi sẽ không bao giờ muốn thấy đoạn mã cụ thể đó (hoặc một cái gì đó giống với nó) trong bất kỳ mã nào tôi duy trì, hoặc nó sẽ là một hành vi phạm tội gần như nổ súng.
Lasse V. Karlsen

6
Chắc chắn, nhưng đó sẽ là "hợp pháp" với "đối tượng" thay vì "động". Bạn chưa thể hiện điều gì thú vị về năng động ở đây.
Eric Lippert

Đối với đối tượng, bạn sẽ phải chuyển nó sang loại thích hợp, để thực sự gọi bất kỳ phương thức nào của nó ... bạn mất chữ ký; bạn có thể yêu cầu mã của mình gọi bất kỳ phương thức nào mà không có lỗi biên dịch và nó bị lỗi khi chạy. Đã vội vàng loại ra, xin lỗi vì không chỉ định. Và @Lasse, tôi đồng ý và có lẽ tôi sẽ không sử dụng động nhiều.
Brian Mains

1
Trường hợp sử dụng cuối cùng không được giải thích
denfromufa

1

Trường hợp sử dụng tốt nhất các biến loại 'động' đối với tôi là khi gần đây, tôi đang viết một lớp truy cập dữ liệu trong ADO.NET ( sử dụng SQLDataReader ) và mã đã gọi các thủ tục lưu trữ đã được viết sẵn. Có hàng trăm thủ tục lưu trữ kế thừa chứa phần lớn logic nghiệp vụ. Lớp truy cập dữ liệu của tôi cần để trả về một số loại dữ liệu có cấu trúc cho lớp logic nghiệp vụ, dựa trên C #, để thực hiện một số thao tác ( mặc dù hầu như không có ). Mỗi thủ tục được lưu trữ trả về tập dữ liệu khác nhau ( cột bảng ). Vì vậy, thay vì tạo ra hàng tá lớp hoặc cấu trúc để giữ dữ liệu được trả về và chuyển nó đến BLL, tôi đã viết đoạn mã dưới đây trông khá thanh lịch và gọn gàng.

public static dynamic GetSomeData(ParameterDTO dto)
        {
            dynamic result = null;
            string SPName = "a_legacy_stored_procedure";
            using (SqlConnection connection = new SqlConnection(DataConnection.ConnectionString))
            {
                SqlCommand command = new SqlCommand(SPName, connection);
                command.CommandType = System.Data.CommandType.StoredProcedure;                
                command.Parameters.Add(new SqlParameter("@empid", dto.EmpID));
                command.Parameters.Add(new SqlParameter("@deptid", dto.DeptID));
                connection.Open();
                using (SqlDataReader reader = command.ExecuteReader())
                {
                    while (reader.Read())
                    {
                        dynamic row = new ExpandoObject();
                        row.EmpName = reader["EmpFullName"].ToString();
                        row.DeptName = reader["DeptName"].ToString();
                        row.AnotherColumn = reader["AnotherColumn"].ToString();                        
                        result = row;
                    }
                }
            }
            return result;
        }

0
  1. Bạn có thể gọi vào các ngôn ngữ động như CPython bằng pythonnet:

dynamic np = Py.Import("numpy")

  1. Bạn có thể truyền tướng cho dynamickhi áp dụng toán tử số trên chúng. Điều này cung cấp loại an toàn và tránh những hạn chế của thuốc generic. Đây là bản chất * gõ vịt:

T y = x * (dynamic)x, Ở đâu typeof(x) is T


0

Một trường hợp sử dụng khác để dynamicgõ là cho các phương thức ảo gặp vấn đề với hiệp phương sai hoặc chống chỉ định. Một ví dụ như vậy là Clonephương thức khét tiếng trả về một đối tượng cùng loại với đối tượng mà nó được gọi. Vấn đề này không được giải quyết hoàn toàn bằng trả về động vì nó bỏ qua việc kiểm tra kiểu tĩnh, nhưng ít nhất bạn không cần phải sử dụng các phôi xấu xí mọi lúc như khi sử dụng đơn giản object. Mặt khác để nói, các diễn viên trở nên ngầm.

public class A
{
    // attributes and constructor here
    public virtual dynamic Clone()
    {
        var clone = new A();
        // Do more cloning stuff here
        return clone;
    }
}

public class B : A
{
    // more attributes and constructor here
    public override dynamic Clone()
    {
        var clone = new B();    
        // Do more cloning stuff here
        return clone;
    }
}    

public class Program
{
    public static void Main()
    {
        A a = new A().Clone();  // No cast needed here
        B b = new B().Clone();  // and here
        // do more stuff with a and b
    }
}
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.