อะไรคือความแตกต่างระหว่างSystem.Dynamic.ExpandoObject
, System.Dynamic.DynamicObject
และdynamic
?
คุณใช้สถานการณ์ประเภทนี้ในสถานการณ์ใด
อะไรคือความแตกต่างระหว่างSystem.Dynamic.ExpandoObject
, System.Dynamic.DynamicObject
และdynamic
?
คุณใช้สถานการณ์ประเภทนี้ในสถานการณ์ใด
คำตอบ:
dynamic
คำหลักที่จะใช้ในการประกาศตัวแปรที่ควรจะปลายที่ถูกผูกไว้
หากคุณต้องการใช้การรวมล่าช้าสำหรับประเภทจริงหรือจินตนาการคุณใช้dynamic
คำหลักและคอมไพเลอร์ทำส่วนที่เหลือ
เมื่อคุณใช้dynamic
คำหลักเพื่อโต้ตอบกับอินสแตนซ์ปกติDLR จะทำการโทรข้ามขอบไปยังวิธีปกติของอินสแตนซ์
IDynamicMetaObjectProvider
อินเตอร์เฟซที่ช่วยให้ชั้นเรียนที่จะควบคุมพฤติกรรมของขอบล่าช้าของ
เมื่อคุณใช้dynamic
คีย์เวิร์ดเพื่อโต้ตอบกับIDynamicMetaObjectProvider
การนำไปใช้งาน DLR จะเรียกIDynamicMetaObjectProvider
เมธอดและวัตถุเองจะตัดสินใจว่าจะทำอย่างไร
ExpandoObject
และเรียนการใช้งานของDynamicObject
IDynamicMetaObjectProvider
ExpandoObject
เป็นคลาสแบบง่ายที่ช่วยให้คุณเพิ่มสมาชิกในอินสแตนซ์และใช้พวกเขาdynamic
เป็นพันธมิตร
DynamicObject
เป็นการใช้งานขั้นสูงเพิ่มเติมซึ่งสามารถสืบทอดเพื่อให้พฤติกรรมที่กำหนดเองได้อย่างง่ายดาย
ฉันจะพยายามให้คำตอบที่ชัดเจนสำหรับคำถามนี้เพื่ออธิบายอย่างชัดเจนว่าความแตกต่างระหว่างไดนามิกExpandoObject
และDynamicObject
อะไร
เร็วมากdynamic
เป็นคำหลัก มันไม่ได้เป็นประเภทต่อ se มันเป็นคำหลักที่บอกคอมไพเลอร์ที่จะละเว้นการตรวจสอบประเภทคงที่ในขณะออกแบบและแทนที่จะใช้สายผูกพันในเวลาทำงาน ดังนั้นเราจะไม่ใช้เวลามากdynamic
ในการตอบคำถามนี้
ExpandoObject
และDynamicObject
เป็นประเภทแน่นอน บนพื้นผิวพวกเขาดูคล้ายกันมาก IDynamicMetaObjectProvider
ทั้งชั้นเรียนใช้ อย่างไรก็ตามขุดลึกลงไปแล้วคุณจะพบว่ามันไม่เหมือนกันเลย
DynamicObject เป็นการใช้งานบางส่วนของIDynamicMetaObjectProvider
ความหมายล้วนๆเพื่อเป็นจุดเริ่มต้นสำหรับนักพัฒนาในการใช้ประเภทที่กำหนดเองของพวกเขาเองสนับสนุนการจัดส่งแบบไดนามิกที่มีการจัดเก็บข้อมูลพื้นฐานที่กำหนดเองและพฤติกรรมการดึงเพื่อให้การทำงานแบบไดนามิก
กล่าวโดยย่อให้ใช้ DynamicObject เมื่อคุณต้องการสร้างประเภทของคุณเองที่สามารถใช้กับ DLR และทำงานกับพฤติกรรมที่กำหนดเองใด ๆ ที่คุณต้องการ
ตัวอย่าง: ลองนึกภาพว่าคุณต้องการมีประเภทแบบไดนามิกที่ส่งกลับค่าเริ่มต้นที่กำหนดเองเมื่อใดก็ตามที่มีการพยายามรับสมาชิกที่ไม่มีอยู่ (เช่นไม่ได้ถูกเพิ่มในขณะใช้งาน) และค่าเริ่มต้นนั้นจะบอกว่า "ฉันขอโทษไม่มีคุกกี้ในขวดนี้!" หากคุณต้องการวัตถุแบบไดนามิกที่ทำงานเช่นนี้คุณจะต้องควบคุมสิ่งที่เกิดขึ้นเมื่อไม่พบเขตข้อมูล ExpandoObject จะไม่ยอมให้คุณทำเช่นนี้ ดังนั้นคุณจะต้องสร้างรูปแบบของคุณเองด้วยที่ไม่ซ้ำกันความละเอียดสมาชิกแบบไดนามิก (ส่ง) ExpandoObject
พฤติกรรมและการใช้งานที่แทนตัวพร้อม
คุณสามารถสร้างประเภทดังต่อไปนี้: (หมายเหตุรหัสด้านล่างเป็นเพียงภาพประกอบและอาจไม่ทำงานหากต้องการเรียนรู้เกี่ยวกับวิธีการใช้ DynamicObject อย่างถูกต้องมีบทความและบทแนะนำมากมายที่อื่น)
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;
}
}
ทีนี้เราสามารถใช้คลาสจินตภาพนี้ที่เราเพิ่งสร้างเป็นแบบไดนามิกที่มีพฤติกรรมที่กำหนดเองมากถ้าไม่มีฟิลด์
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
เป็นการใช้งานแบบเต็มรูปแบบIDynamicMetaObjectProvider
ซึ่งทีมงาน. NET Framework ได้ทำการตัดสินใจทั้งหมดสำหรับคุณแล้ว สิ่งนี้มีประโยชน์หากคุณไม่ต้องการพฤติกรรมที่กำหนดเองใด ๆ และคุณรู้สึกว่า ExpandoObject ใช้ได้ดีพอสำหรับคุณ (90% ของเวลาExpandoObject
นั้นดีพอ) ตัวอย่างเช่นดูต่อไปนี้และสำหรับ ExpandoObject ผู้ออกแบบเลือกที่จะโยนข้อยกเว้นหากไม่มีสมาชิกแบบไดนามิก
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) { ... }
ดังนั้นการสรุปExpandoObject
จึงเป็นเพียงวิธีหนึ่งที่เลือกไว้ล่วงหน้าเพื่อขยาย DynamicObject ด้วยพฤติกรรมการจัดส่งแบบไดนามิกบางอย่างที่อาจเป็นไปได้สำหรับคุณแต่อาจไม่ขึ้นอยู่กับความต้องการเฉพาะของคุณ
ในขณะที่DyanmicObject
เป็นผู้ช่วย BaseType ที่ทำให้การใช้งานประเภทของคุณเองด้วยพฤติกรรมแบบไดนามิกที่ไม่ซ้ำกันง่ายและสะดวก
DynamicObject
: เมื่อแทนที่TryGetMember
หากคุณส่งคืนค่าเท็จRuntimeBinderException
จะถูกโยนทิ้งเมื่อพยายามเข้าถึงคุณสมบัติที่ไม่มีอยู่ true
สำหรับข้อมูลโค้ดในการทำงานจริงที่คุณควรจะกลับ
ตามข้อกำหนดภาษา C # dynamic
เป็นการประกาศประเภท คือdynamic x
หมายความว่าตัวแปรที่มีชนิดx
dynamic
DynamicObject
เป็นประเภทที่ทำให้ง่ายต่อการใช้งานIDynamicMetaObjectProvider
และดังนั้นจึงแทนที่พฤติกรรมการผูกเฉพาะสำหรับประเภท
ExpandoObject
เป็นประเภทที่ทำหน้าที่เหมือนกระเป๋าทรัพย์สิน เช่นคุณสามารถเพิ่มคุณสมบัติวิธีการและอื่น ๆ ให้กับอินสแตนซ์แบบไดนามิกของประเภทนี้ในขณะทำงาน
dynamic
ไม่ใช่ประเภทที่แท้จริง ... เป็นเพียงคำแนะนำในการบอกคอมไพเลอร์ให้ใช้การรวมภายหลังสำหรับตัวแปรนี้ dynamic
ตัวแปรถูกประกาศตามจริงobject
ใน MSIL
ตัวอย่างข้างต้นของการไม่บอกความแตกต่างอย่างเห็นได้ชัดเพราะมันเป็นพื้นการใช้ฟังก์ชั่นที่มีให้แล้วโดยDynamicObject
ExpandoObject
ในลิงก์ทั้งสองที่กล่าวถึงด้านล่างมีความชัดเจนมากว่าด้วยความช่วยเหลือของDynamicObject
มันเป็นไปได้ที่จะรักษา / เปลี่ยนประเภทที่แท้จริง ( XElement
ในตัวอย่างที่ใช้ในลิงค์ด้านล่าง) และควบคุมคุณสมบัติและวิธีการต่างๆได้ดีขึ้น
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;
}
}
}