Jawaban:
Kata dynamic
kunci tersebut digunakan untuk mendeklarasikan variabel yang harus diikat.
Jika Anda ingin menggunakan pengikatan yang lebih lambat, untuk semua tipe nyata atau yang dibayangkan, Anda menggunakan dynamic
kata kunci dan sisanya adalah kompiler.
Saat Anda menggunakan dynamic
kata kunci untuk berinteraksi dengan mesin virtual normal, DLR melakukan panggilan yang terlambat ke metode normal mesin virtual tersebut.
The IDynamicMetaObjectProvider
antarmuka memungkinkan kelas untuk mengambil kendali dari perilaku akhir-terikat nya.
Ketika Anda menggunakan dynamic
kata kunci untuk berinteraksi dengan IDynamicMetaObjectProvider
implementasi, DLR memanggil IDynamicMetaObjectProvider
metode dan objek itu sendiri memutuskan apa yang harus dilakukan.
The ExpandoObject
dan DynamicObject
kelas implementasi dari IDynamicMetaObjectProvider
.
ExpandoObject
adalah kelas sederhana yang memungkinkan Anda untuk menambahkan anggota ke instance dan menggunakannya sebagai dynamic
sekutu.
DynamicObject
adalah implementasi yang lebih maju yang dapat diwarisi untuk dengan mudah memberikan perilaku yang disesuaikan.
Saya akan mencoba memberikan jawaban yang lebih jelas untuk pertanyaan ini, untuk menjelaskan dengan jelas apa perbedaan antara dinamis, ExpandoObject
dan DynamicObject
.
Sangat cepat, dynamic
adalah kata kunci. Ini bukan tipe per-se. Ini adalah kata kunci yang memberitahu kompiler untuk mengabaikan pengecekan tipe statis pada waktu desain dan alih-alih menggunakan pengikatan yang terlambat pada waktu berjalan. Jadi kita tidak akan menghabiskan banyak waktu dynamic
di sisa jawaban ini.
ExpandoObject
dan DynamicObject
memang tipe. Di PERMUKAAN, mereka terlihat sangat mirip satu sama lain. Kedua kelas menerapkan IDynamicMetaObjectProvider
. Namun, gali lebih dalam dan Anda akan menemukan bahwa mereka TIDAK serupa.
DynamicObject adalah implementasi parsial yang IDynamicMetaObjectProvider
murni dimaksudkan sebagai titik awal bagi pengembang untuk mengimplementasikan tipe kustom mereka sendiri yang mendukung pengiriman dinamis dengan penyimpanan yang mendasari kustom dan perilaku pengambilan untuk membuat pengiriman dinamis berfungsi.
Singkatnya, gunakan DynamicObject ketika Anda ingin membuat tipe SENDIRI yang dapat digunakan dengan DLR dan bekerja dengan perilaku CUSTOM apa pun yang Anda inginkan.
Contoh: Bayangkan bahwa Anda ingin memiliki tipe dinamis yang mengembalikan default khusus setiap kali mencoba anggota yang TIDAK ada (yaitu belum ditambahkan pada waktu berjalan). Dan default itu akan berkata, "Maaf, tidak ada cookie di toples ini!". Jika Anda menginginkan objek dinamis yang berperilaku seperti ini, Anda harus mengontrol apa yang terjadi ketika bidang tidak ditemukan. ExpandoObject tidak akan membiarkan Anda melakukan ini. Jadi, Anda harus membuat tipe Anda sendiri dengan perilaku resolusi (pengiriman) anggota dinamis yang unik dan menggunakannya daripada yang sudah jadi ExpandoObject
.
Anda dapat membuat jenis sebagai berikut: (Catatan, kode di bawah ini hanya untuk ilustrasi dan mungkin tidak berjalan. Untuk mempelajari tentang cara menggunakan DynamicObject dengan benar, ada banyak artikel dan tutorial di tempat lain.)
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;
}
}
Sekarang, kita bisa menggunakan kelas imajiner yang baru saja kita buat sebagai tipe dinamis yang memiliki perilaku sangat khusus jika bidang tidak ada.
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
adalah implementasi LENGKAP dari IDynamicMetaObjectProvider
, di mana tim .NET Framework telah membuat semua keputusan ini untuk Anda. Ini berguna jika Anda tidak memerlukan perilaku khusus, dan Anda merasa bahwa ExpandoObject bekerja cukup baik untuk Anda (90% dari waktu, ExpandoObject
cukup baik). Jadi misalnya, lihat yang berikut ini, dan untuk ExpandoObject, desainer memilih untuk melemparkan pengecualian jika anggota dinamis tidak ada.
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) { ... }
Jadi untuk meringkas, ExpandoObject
hanyalah satu cara yang dipilih sebelumnya untuk memperluas DynamicObject dengan perilaku pengiriman dinamis tertentu yang mungkin akan bekerja untuk Anda , tetapi mungkin tidak tergantung pada kebutuhan khusus Anda.
Sedangkan, DyanmicObject
adalah tipe dasar pembantu yang membuat menerapkan tipe Anda sendiri dengan perilaku dinamis yang unik sederhana dan mudah.
Tutorial bermanfaat yang menjadi dasar dari banyak contoh sumber di atas.
DynamicObject
: ketika menimpa TryGetMember
, jika Anda mengembalikan false, RuntimeBinderException
akan dilemparkan ketika mencoba mengakses ke properti yang tidak ada. Agar snipet benar-benar berfungsi, Anda harus kembali true
.
Menurut spesifikasi bahasa C # dynamic
adalah deklarasi jenis. Yaitu dynamic x
berarti variabel x
memiliki tipedynamic
.
DynamicObject
adalah tipe yang membuatnya mudah diimplementasikan IDynamicMetaObjectProvider
dan dengan demikian mengesampingkan perilaku mengikat spesifik untuk tipe tersebut.
ExpandoObject
adalah jenis yang bertindak seperti tas properti. Yaitu Anda dapat menambahkan properti, metode, dan sebagainya ke contoh dinamis dari tipe ini saat runtime.
dynamic
bukan tipe aktual ... itu hanya sebuah petunjuk untuk memberitahu kompiler untuk menggunakan pengikatan akhir untuk variabel ini. dynamic
variabel sebenarnya dideklarasikan seperti object
dalam MSIL
Contoh di atas DynamicObject
tidak memberi tahu perbedaannya, karena pada dasarnya menerapkan fungsi yang sudah disediakan olehExpandoObject
.
Dalam dua tautan yang disebutkan di bawah ini, sangat jelas bahwa dengan bantuan DynamicObject
, dimungkinkan untuk melestarikan / mengubah tipe aktual ( XElement
dalam contoh yang digunakan dalam tautan di bawah) dan kontrol yang lebih baik pada properti dan metode.
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;
}
}
}