Câu trả lời:
Các dynamic
từ 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 dynamic
từ khóa và trình biên dịch làm phần còn lại.
Khi bạn sử dụng dynamic
từ 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 IDynamicMetaObjectProvider
giao 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 dynamic
từ khóa để tương tác với một IDynamicMetaObjectProvider
triển khai, DLR gọi các IDynamicMetaObjectProvider
phương thức và chính đối tượng quyết định phải làm gì.
Các lớp ExpandoObject
và DynamicObject
đang triển khai IDynamicMetaObjectProvider
.
ExpandoObject
là 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.
DynamicObject
là 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 ExpandoObject
và DynamicObject
.
Rất nhanh chóng, dynamic
là 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 dynamic
cho phần còn lại của câu trả lời này.
ExpandoObject
và DynamicObject
thự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 IDynamicMetaObjectProvider
hoà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!")
ExpandoObject
là 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, ExpandoObject
là đủ 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, ExpandoObject
chỉ đơ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 đó, DyanmicObject
là 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, RuntimeBinderException
sẽ 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 # dynamic
là một khai báo kiểu. Nghĩa dynamic x
là biến x
có kiểu dynamic
.
DynamicObject
là một loại giúp dễ dàng thực hiện IDynamicMetaObjectProvider
và do đó ghi đè hành vi ràng buộc cụ thể cho loại.
ExpandoObject
là 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.
dynamic
khô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. dynamic
các biến thực sự được khai báo như object
trong MSIL
Ví dụ trên DynamicObject
khô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ế ( XElement
trong 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;
}
}
}