Câu trả lời:
Các dynamictừ khóa được sử dụng để khai báo các biến cần được cuối-bound.
Nếu bạn muốn sử dụng liên kết muộn, đối với bất kỳ loại thực hoặc tưởng tượng, bạn sử dụng dynamictừ khóa và trình biên dịch làm phần còn lại.
Khi bạn sử dụng dynamictừ khóa để tương tác với một cá thể bình thường, DLR thực hiện các cuộc gọi bị ràng buộc muộn đến các phương thức thông thường của cá thể.
Các IDynamicMetaObjectProvidergiao diện cho phép một lớp học để kiểm soát hành vi cuối-bound của nó.
Khi bạn sử dụng dynamictừ khóa để tương tác với một IDynamicMetaObjectProvidertriển khai, DLR gọi các IDynamicMetaObjectProviderphương thức và chính đối tượng quyết định phải làm gì.
Các lớp ExpandoObjectvà DynamicObjectđang triển khai IDynamicMetaObjectProvider.
ExpandoObjectlà một lớp đơn giản cho phép bạn thêm các thành viên vào một thể hiện và sử dụng chúng dynamicđồng minh.
DynamicObjectlà một triển khai nâng cao hơn có thể được kế thừa để dễ dàng cung cấp hành vi tùy chỉnh.
Tôi sẽ cố gắng cung cấp một câu trả lời rõ ràng hơn cho câu hỏi này, để giải thích rõ ràng sự khác biệt giữa động ExpandoObjectvà DynamicObject.
Rất nhanh chóng, dynamiclà một từ khóa. Nó không phải là một loại per-se. Đó là một từ khóa yêu cầu trình biên dịch bỏ qua kiểm tra kiểu tĩnh tại thời điểm thiết kế và thay vào đó sử dụng liên kết trễ vào thời gian chạy. Vì vậy, chúng tôi sẽ không dành nhiều thời gian dynamiccho phần còn lại của câu trả lời này.
ExpandoObjectvà DynamicObjectthực sự là các loại. Trên BỀ MẶT, chúng trông rất giống nhau. Cả hai lớp thực hiện IDynamicMetaObjectProvider. Tuy nhiên, đào sâu hơn và bạn sẽ thấy chúng KHÔNG giống nhau chút nào.
DynamicObject là một triển khai một phần IDynamicMetaObjectProviderhoàn toàn có nghĩa là điểm khởi đầu để các nhà phát triển triển khai các loại tùy chỉnh của riêng họ hỗ trợ công văn động với hành vi lưu trữ và truy xuất cơ sở tùy chỉnh để làm cho công văn động hoạt động.
Nói tóm lại, hãy sử dụng DynamicObject khi bạn muốn tạo các loại OWN có thể được sử dụng với DLR và hoạt động với bất kỳ hành vi TÙY CHỈ nào bạn muốn.
Ví dụ: Hãy tưởng tượng rằng bạn muốn có một loại động trả về mặc định tùy chỉnh bất cứ khi nào có được một thành viên KHÔNG tồn tại (tức là chưa được thêm vào lúc chạy). Và mặc định đó sẽ nói, "Tôi xin lỗi, không có cookie trong bình này!". Nếu bạn muốn một đối tượng động hoạt động như thế này, bạn sẽ cần kiểm soát những gì xảy ra khi không tìm thấy trường. ExpandoObject sẽ không cho phép bạn làm điều này. Vì vậy, bạn sẽ cần tạo loại của riêng mình với hành vi (gửi) thành viên động duy nhất và sử dụng loại đó thay vì được tạo sẵn ExpandoObject.
Bạn có thể tạo một loại như sau: (Lưu ý, đoạn mã dưới đây chỉ để minh họa và có thể không chạy. Để tìm hiểu về cách sử dụng DynamicObject đúng cách, có nhiều bài viết và hướng dẫn ở nơi khác.)
public class MyNoCookiesInTheJarDynamicObject : DynamicObject
{
Dictionary<string, object> properties = new Dictionary<string, object>();
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (properties.ContainsKey(binder.Name))
{
result = properties[binder.Name];
return true;
}
else
{
result = "I'm sorry, there are no cookies in this jar!"; //<-- THIS IS OUR
CUSTOM "NO COOKIES IN THE JAR" RESPONSE FROM OUR DYNAMIC TYPE WHEN AN UNKNOWN FIELD IS ACCESSED
return false;
}
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
properties[binder.Name] = value;
return true;
}
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
dynamic method = properties[binder.Name];
result = method(args[0].ToString(), args[1].ToString());
return true;
}
}
Bây giờ, chúng ta có thể sử dụng lớp tưởng tượng này mà chúng ta vừa tạo như một kiểu động có hành vi rất tùy chỉnh nếu trường không tồn tại.
dynamic d = new MyNoCookiesInTheJarDynamicObject();
var s = d.FieldThatDoesntExist;
//in our contrived example, the below should evaluate to true
Assert.IsTrue(s == "I'm sorry, there are no cookies in this jar!")
ExpandoObjectlà một triển khai ĐẦY ĐỦ IDynamicMetaObjectProvider, trong đó nhóm .NET Framework đã đưa ra tất cả các quyết định này cho bạn. Điều này hữu ích nếu bạn không cần bất kỳ hành vi tùy chỉnh nào và bạn cảm thấy ExpandoObject hoạt động đủ tốt cho bạn (90% thời gian, ExpandoObjectlà đủ tốt). Vì vậy, ví dụ, xem phần sau đây và đối với ExpandoObject, các nhà thiết kế đã chọn đưa ra một ngoại lệ nếu thành viên động không tồn tại.
dynamic d = new ExpandoObject();
/*
The ExpandoObject designers chose that this operation should result in an
Exception. They did not have to make that choice, null could
have been returned, for example; or the designers could've returned a "sorry no cookies in the jar" response like in our custom class. However, if you choose to use
ExpandoObject, you have chosen to go with their particular implementation
of DynamicObject behavior.
*/
try {
var s = d.FieldThatDoesntExist;
}
catch(RuntimeBinderException) { ... }
Vì vậy, để tóm tắt, ExpandoObjectchỉ đơn giản là một cách được chọn trước để mở rộng DynamicObject với các hành vi điều phối động nhất định có thể sẽ phù hợp với bạn , nhưng có thể không phụ thuộc vào nhu cầu cụ thể của bạn.
Trong khi đó, DyanmicObjectlà một BaseType trợ giúp giúp thực hiện các kiểu của riêng bạn với các hành vi động độc đáo đơn giản và dễ dàng.
Một hướng dẫn hữu ích mà phần lớn nguồn ví dụ ở trên được dựa trên.
DynamicObject: khi ghi đè TryGetMember, nếu bạn trả về sai, RuntimeBinderExceptionsẽ bị ném khi cố gắng truy cập vào tài sản không tồn tại. Để đoạn trích thực sự hoạt động, bạn nên quay lại true.
Theo đặc tả ngôn ngữ C # dynamiclà một khai báo kiểu. Nghĩa dynamic xlà biến xcó kiểu dynamic.
DynamicObjectlà một loại giúp dễ dàng thực hiện IDynamicMetaObjectProvidervà do đó ghi đè hành vi ràng buộc cụ thể cho loại.
ExpandoObjectlà một loại hoạt động như một túi tài sản. Tức là bạn có thể thêm các thuộc tính, phương thức và vv cho các trường hợp động của loại này khi chạy.
dynamickhông phải là một loại thực tế ... nó chỉ là một gợi ý để nói cho trình biên dịch sử dụng liên kết muộn cho biến này. dynamiccác biến thực sự được khai báo như objecttrong MSIL
Ví dụ trên DynamicObjectkhông cho biết sự khác biệt rõ ràng, vì về cơ bản, nó thực hiện chức năng đã được cung cấp bởi ExpandoObject.
Trong hai liên kết được đề cập dưới đây, rất rõ ràng rằng với sự trợ giúp của DynamicObject, có thể bảo tồn / thay đổi loại thực tế ( XElementtrong ví dụ được sử dụng trong các liên kết bên dưới) và kiểm soát tốt hơn các thuộc tính và phương thức.
public class DynamicXMLNode : DynamicObject
{
XElement node;
public DynamicXMLNode(XElement node)
{
this.node = node;
}
public DynamicXMLNode()
{
}
public DynamicXMLNode(String name)
{
node = new XElement(name);
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
XElement setNode = node.Element(binder.Name);
if (setNode != null)
setNode.SetValue(value);
else
{
if (value.GetType() == typeof(DynamicXMLNode))
node.Add(new XElement(binder.Name));
else
node.Add(new XElement(binder.Name, value));
}
return true;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
XElement getNode = node.Element(binder.Name);
if (getNode != null)
{
result = new DynamicXMLNode(getNode);
return true;
}
else
{
result = null;
return false;
}
}
}