ExpandoObject'in gerçek faydaları nelerdir?


587

ExpandoObject sınıf çalışma zamanında bir nesnenin üzerine .NET 4 keyfi set özellikleri sağlayan eklenen.

Bunun, a Dictionary<string, object>, hatta bir Hashtable kullanmanın avantajları var mı? Bildiğim kadarıyla, bu biraz daha özlü sözdizimi ile erişebileceğiniz bir karma tablodan başka bir şey değildir.

Örneğin, neden:

dynamic obj = new ExpandoObject();
obj.MyInt = 3;
obj.MyString = "Foo";
Console.WriteLine(obj.MyString);

Gerçekten daha iyi veya önemli ölçüde farklı:

var obj = new Dictionary<string, object>();
obj["MyInt"] = 3;
obj["MyString"] = "Foo";

Console.WriteLine(obj["MyString"]);

Çalışma zamanında belirlenecek bir türü kullandığınızın belli olmaması dışında, yalnızca rastgele bir sözlük türü kullanmak yerine ExpandoObject kullanılarak elde edilen gerçek avantajlar.

Yanıtlar:


689

Bahsettiğiniz MSDN makalesini yazdığım için, sanırım buna cevap vermeliyim.

İlk olarak, bu soruyu bekledim ve bu yüzden ExpandoObject: C # 4.0'da Dinamik: ExpandoObject'e Giriş için az çok gerçek bir kullanım durumu gösteren bir blog yazısı yazdım .

Kısaca, ExpandoObject karmaşık hiyerarşik nesneler oluşturmanıza yardımcı olabilir. Örneğin, bir sözlük içinde bir sözlüğünüz olduğunu düşünün:

Dictionary<String, object> dict = new Dictionary<string, object>();
Dictionary<String, object> address = new Dictionary<string,object>();
dict["Address"] = address;
address["State"] = "WA";
Console.WriteLine(((Dictionary<string,object>)dict["Address"])["State"]);

Daha derin olan hiyerarşi, çirkin koddur. ExpandoObject ile zarif ve okunabilir halde kalır.

dynamic expando = new ExpandoObject();
expando.Address = new ExpandoObject();
expando.Address.State = "WA";
Console.WriteLine(expando.Address.State);

İkincisi, daha önce de belirtildiği gibi, ExpandoObject INotifyPropertyChanged arabirimini uygular, bu da özellikler üzerinde bir sözlükten daha fazla kontrol sağlar.

Son olarak, ExpandoObject'e aşağıdaki gibi etkinlikler ekleyebilirsiniz:

class Program
{
   static void Main(string[] args)
   {
       dynamic d = new ExpandoObject();

       // Initialize the event to null (meaning no handlers)
       d.MyEvent = null;

       // Add some handlers
       d.MyEvent += new EventHandler(OnMyEvent);
       d.MyEvent += new EventHandler(OnMyEvent2);

       // Fire the event
       EventHandler e = d.MyEvent;

       e?.Invoke(d, new EventArgs());
   }

   static void OnMyEvent(object sender, EventArgs e)
   {
       Console.WriteLine("OnMyEvent fired by: {0}", sender);
   }

   static void OnMyEvent2(object sender, EventArgs e)
   {
       Console.WriteLine("OnMyEvent2 fired by: {0}", sender);
   }
}

Ayrıca, hiçbir şeyin etkinlik bağımsız değişkenlerini dinamik bir şekilde kabul etmenizi engellemediğini unutmayın. Başka bir deyişle, kullanmak yerine , işleyicinin ikinci argümanının olmasına neden EventHandlerolacak şekilde kullanabilirsiniz .EventHandler<dynamic>dynamic


53
İlginç. Bilgi: etkinlikler için teşekkürler. Bu benim için yeni bir şeydi.
Reed Copsey

16
@AlexandraRusina, bunu söylediğinde bir olay olduğunu nereden biliyor d.MyEvent = null;, yoksa değil mi?
Shimmy Weitzhandler

20
Belki bir şey eksik, ama bu olay değil - bu temsilci tipi basit bir özelliktir.
Sergey Berezovskiy

7
İlk blok anonim tipler kullanılarak yazılabilir: var expando = new { Address = new { State = "WA" } }; Console.WriteLine(expando.Address.State);Bunu daha okunabilir ama ymmv buluyorum. Ve statik olarak yazıldığı düşünüldüğünde, bu bağlamda daha kullanışlıdır.
nawfal

13
@nawfal bu doğru değil - anonim bir Expando'dan farklıdır. Anonim bir tür oluşturuyorsunuz ve bu tür öğelere rastgele özellikler ekleyemiyorsunuz.
Dr Blowhard

75

Bir avantaj, bağlayıcı senaryolar içindir. Veri ızgaraları ve özellik ızgaraları, TypeDescriptor sistemi aracılığıyla dinamik özellikleri alır. Buna ek olarak, WPF veri bağlama dinamik özellikleri anlayacaktır, böylece WPF denetimleri bir ExpandoObject öğesine sözlükten daha kolay bağlanabilir.

Sözlük girişlerinden ziyade DLR özelliklerini bekleyecek dinamik dillerle birlikte çalışabilirlik de bazı senaryolarda dikkate alınabilir.


6
Dinamik nesnelere o veri bağlama bozuldu görünüyor . Rapor eden kullanıcı eisenbergeffect burada SO'da ve caliburn.micro koordinatörüdür. @AlexandraRusina hata durumu ve durumu "Düzeltmez" hakkında yorum yapabilir
surfmuggle

2
Bu meraklı için, Şu anda bağlamak mümkün duyuyorum List<dynamic>ve IEnumerable<dynamic>kullanma WPF4
Graham Bass

47

Benim için asıl fayda, XAML'den tamamen zahmetsiz veri bağlaması:

public dynamic SomeData { get; set; }

...

SomeData.WhatEver = "Yo Man!";

...

 <TextBlock Text="{Binding SomeData.WhatEver}" />

28

Üzerinde kurulmuş diğer dillerle birlikte çalışabileceğim bir DLRneden. Onları a alamazsınız Dictionary<string, object>çünkü o değil IDynamicMetaObjectProvider. Eklenen diğer bir fayda ise INotifyPropertyChanged, WPF'nin veri oluşturma dünyasında da Dictionary<K,V>size sağlayabileceklerin ötesinde ek faydaları olduğu anlamına geliyor .


19

Her şey programcının rahatlığıyla ilgilidir. Bu nesne ile hızlı ve kirli programlar yazmayı hayal edebiliyorum.


9
@J. Hendrix, unutma ki "kirli" dedi. Intellisense'in dezavantajı vardır, ancak hata ayıklamayı ve hata yakalamayı kolaylaştırır. Garip (ve her zaman nadir) bir durumla uğraşmadıkça kişisel olarak hala dinamik türlere göre statik tercih ederim.
Phil

Kolaylık için +1. Ancak anonim türlerin basit bir özellik torbası olarak eşit derecede uygun olabileceğini ve statikliği için daha iyi olabileceğini düşünüyorum.
nawfal

1
Üretim kodunda kullanmak istemem, ancak test kodunda çok uygundur ve çok güzel görünmesini sağlayabilir.
Tobias

14

Sözdizimsel bir yararı olacağını düşünüyorum, çünkü artık sözlük kullanarak dinamik olarak eklenen özellikleri "sahtecilik" yapmayacaksınız.

Bunu ve dinamik dillerle birlikte çalışacağını düşünüyorum.


11

Gelen yapılandırılmış veriler (ör. XML, Json) için dinamik geçici türler oluşturmak için ExpandoObject kullanma hakkındaki harika MSDN makalesinden bir örnek .

ExpandoObject'ün dinamik özelliğine de temsilci atayabiliriz :

dynamic person = new ExpandoObject();
person.FirstName = "Dino";
person.LastName = "Esposito";

person.GetFullName = (Func<String>)(() => { 
  return String.Format("{0}, {1}", 
    person.LastName, person.FirstName); 
});

var name = person.GetFullName();
Console.WriteLine(name);

Böylece çalışma zamanında dinamik nesneye bir miktar mantık enjekte etmemizi sağlar. Bu nedenle, lambda ifadeleri, kapaklar, dinamik anahtar kelime ve DynamicObject sınıfı ile birlikte , JavaScript veya PHP gibi dinamik dillerden bildiğimiz C # kodumuza fonksiyonel programlama bazı unsurları ekleyebiliriz.


4

Bunun kullanışlı olduğu bazı durumlar vardır. Örneğin Modüler bir kabuk için kullanacağım. Her modül, kendi ayarlarına bağlı kendi Yapılandırma İletişim Kutusunu tanımlar. Ben bir ExpandoObject ile Datacontext sağlamak ve değerleri benim depolama Depolama kaydedin. Bu şekilde Yapılandırma İletişim Kutusu yazarının bir Değere Bağlanması gerekir ve bu değer otomatik olarak oluşturulur ve kaydedilir. (Ve elbette bu ayarları kullanmak için modüle sağlanmıştır)

Kullanımı sözlükten daha kolaydır. Ancak herkes, dahili olarak bunun bir Sözlük olduğunu bilmelidir.

LINQ sadece sözdizimsel şeker gibi, ama bazen işleri kolaylaştırır.

Sorunuzu doğrudan cevaplamak için: Yazmak ve okumak daha kolaydır. Ancak teknik olarak aslında bir Dictionary<string,object>(değerleri listelemek için bir tanesine bile dökebilirsiniz).


-1
var obj = new Dictionary<string, object>;
...
Console.WriteLine(obj["MyString"]);

Bence her şeyin bir ToString () özelliği olduğu için çalıştığını düşünüyorum, aksi takdirde onun türünü bilmeniz ve 'nesneyi' bu türe atamanız gerekir.


Bunlardan bazıları diğerlerinden daha sık faydalıdır, kapsamlı olmaya çalışıyorum.

  1. Bir koleksiyona erişmek, bu durumda, daha doğrudan nokta gösterimini kullanarak etkili bir şekilde "sözlük" olan çok daha doğal olabilir.

  2. Bu gerçekten güzel bir Tuple olarak kullanılabilir gibi görünüyor. Yine de üyelerinize "Item1", "Item2" vb. Diyebilirsiniz ... ama artık bir Tuple'ın aksine değişebilir. Bunun, akıllıca destek eksikliğinin büyük dezavantajı var.

  3. Sözlük gibi hissediyorum, "dizeleri olarak üye adları" ile rahatsız olabilir, çok "dizeleri yürütme" gibi olduğunu hissedebilirsiniz, ve kodlama adlandırma kuralları ve morphemes ve hileler kod çalışırken nasıl kullanılacağını anlamak :-P

  4. ExpandoObject'e bir değer atayabilir misiniz, yoksa sadece üyeleri mi? Dinamik / dinamik [] ile karşılaştırın ve karşılaştırın, ihtiyaçlarınıza en uygun olanı kullanın.

  5. Dinamik / dinamik [] bir foreach döngüsünde çalıştığını sanmıyorum, var kullanmak zorunda, ama muhtemelen ExpandoObject kullanabilirsiniz.

  6. Dinamik bir sınıfta veri üyesi olarak kullanılamaz, belki de en azından bir tür anahtar kelime gibi olduğundan, umarım ExpandoObject ile yapabilirsiniz.

  7. Ben bir ExpandoObject "olduğunu", kullanılan çok dinamik şeyler olduğu türleri dayalı farklılaşan kod ile, çok genel şeyler etiketlemek için yararlı olabilir bekliyoruz.


Aynı anda birden fazla seviyeyi delebilirseniz iyi olun.

var e = new ExpandoObject();
e.position.x = 5;
etc...

Mümkün olan en iyi örnek bu değil, kendi projelerinizde uygun olan zarif kullanımları hayal edin.

Bunlardan bazılarını kod oluşturamaz ve sonuçları anlaşılır hale getiremezsiniz. Bunun nasıl çalışacağından emin değilim.

Üyelerin yanı sıra bir değeri olabilir, iyi olun.

var fifteen = new ExpandoObject();
fifteen = 15;
fifteen.tens = 1;
fifteen.units = 5;
fifteen.ToString() = "fifteen";
etc...

-3

ValueTuples'dan sonra ExpandoObject sınıfının kullanımı nedir? ExpandoObject ile bu 6 satır kodu:

dynamic T = new ExpandoObject();
T.x = 1;
T.y = 2;
T.z = new ExpandoObject();
T.z.a = 3;
T.b= 4;

tuples ile tek bir satırda yazılabilir:

var T = (x: 1, y: 2, z: (a: 3, b: 4));

grup sözdiziminin yanı sıra, güçlü bir tür çıkarım ve uyumsuz desteğe de sahipsiniz


1
Örnekleriniz, değer demetiyle Tc = 5 yazamayacağınız anlamında aynı değildir; bitirdikten sonra T. tanımlayın. ExpandoObject ile bunu yapabilirsiniz çünkü dinamiktir. Değer demetiyle ilgili örnek, anonim tür bildirme ile çok aynıdır. Örneğin: var T2 = yeni {x = 1, y = 2, z = yeni {a = 3, b = 4}};
LxL

Neden tanımlamaksızın Tc = 5 yazmam gerekiyor? ExpandoObject sadece .net içinde eksik olmayan COM nesneleri ile uğraşırken yararlıdır. Aksi takdirde, bu ExpandoObject'i asla kullanmam, çünkü hem tasarım zamanında hem de çalışma zamanında kirli ve buggy.
Müh. M.Hamdy

1
İlk önce z'ye (a: 3, b: 4) atandınız ve sonra z'nin ek c özelliğine sahip olmasını istersiniz? Bunu değer tupleiyle yapabilir misin?
LxL

Benim açımdan, farklı amaçlar için tasarlandıkları için ExpandoObject ile değer demetini karşılaştıramazsınız. Yolunuzu karşılaştırarak, dinamik yapı olan ExpandoObject'in tasarlandığı işlevselliği reddettiniz.
LxL
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.