Dinamik nesnenin üyeleri hakkında nasıl düşünebilirim?


131

NET 4'te dynamic anahtar sözcüğüyle bildirilen bir nesneden özellikler sözlüğü ve değerleri almam gerekiyor mu? Bunun için yansıma kullanmak işe yaramayacak gibi görünüyor.

Misal:

dynamic s = new ExpandoObject();
s.Path = "/Home";
s.Name = "Home";

// How do I enumerate the Path and Name properties and get their values?
IDictionary<string, object> propertyValues = ???

Yanıtlar:


32

IDynamicMetaObjectProvider dinamik üye adlarını sağlayabilirse, bunları alabilirsiniz. Bkz getMemberNames apache'ye uygulanmasını PCL kütüphane lisanslı Dynamitey (Nuget bulunabilir), bunun için çalışır ExpandoObjects ve DynamicObjectbu uygulamaya s GetDynamicMemberNamesve diğer IDynamicMetaObjectProviderbir uygulaması olan bir meta nesne sağlar kimin GetDynamicMemberNamesözel test ötelerin olmadanis IDynamicMetaObjectProvider .

Üye isimlerini aldıktan sonra, değeri doğru şekilde elde etmek biraz daha fazla iş ama Doğaçlama bunu yapıyor ama sadece ilginç kısımlara işaret etmek ve mantıklı olması daha zor. İşte dokümantasyon ve yansımadan daha hızlı, ancak, expando için sözlük aramasından daha hızlı olması muhtemel değil, ancak herhangi bir nesne için çalışıyor, expando, dinamik veya orijinal - adını siz koyun.


17
Bu noktaya geldiğiniz için kod: var tTarget = target as IDynamicMetaObjectProvider; if (tTarget! = null) {tList.AddRange (tTarget.GetMetaObject (Expression.Constant (tTarget)). GetDynamicMemberNames ()); }
Flatliner DOA

harika kitaplığınız için teşekkürler. Dinamik bir nesneyi dynamicjson.codeplex.com'a bu kitaplığa döndürürken sorunlar yaşıyordum ve bunu kitaplığınızla genişletebildim.
JJS

1
örnek lütfen.
Demodave

105

ExpandoObject durumunda, ExpandoObject sınıfı aslında IDictionary<string, object>özellikleri için uygular , bu nedenle çözüm çevrim kadar önemsizdir:

IDictionary<string, object> propertyValues = (IDictionary<string, object>)s;

Bunun genel dinamik nesneler için çalışmayacağını unutmayın. Bu durumlarda, IDynamicMetaObjectProvider aracılığıyla DLR'ye geçmeniz gerekecektir.


Bunun için teşekkürler, maalesef örnek biraz fazla basite indirgenmişti. Dinamik bir nesneyi gerçek türünün ne olduğunu bilmeden inceleyebilmem gerekiyor.
Flatliner DOA

2
Bu yalnızca ExpandoObject sınıfının nesneleri için işe yarar; DynamicObject sınıfı, IDictionary uygulamayan ancak bunun yerine IDynamicMetaObjectProvider'ı uygulayan başka bir genişletilebilir sınıftır.
Sharique Abdullah

1
Yine de OP'nin sorusuna cevap veriyor.
Sharique Abdullah

58

Dikkate alınması gereken birkaç senaryo var. Her şeyden önce, nesnenizin türünü kontrol etmeniz gerekir. Bunun için GetType () 'ı çağırabilirsiniz. Tür, IDynamicMetaObjectProvider uygulamazsa, herhangi bir nesnede olduğu gibi yansımayı kullanabilirsiniz. Gibi bir şey:

var propertyInfo = test.GetType().GetProperties();

Ancak, IDynamicMetaObjectProvider uygulamaları için basit yansıma çalışmaz. Temel olarak, bu nesne hakkında daha fazla bilgi sahibi olmanız gerekir. ExpandoObject ise (IDynamicMetaObjectProvider uygulamalarından biri), itowlson tarafından sağlanan yanıtı kullanabilirsiniz. ExpandoObject, özelliklerini bir sözlükte saklar ve dinamik nesnenizi bir sözlüğe dönüştürebilirsiniz.

DynamicObject ise (başka bir IDynamicMetaObjectProvider uygulaması), o zaman bu DynamicObject'in sunduğu yöntemleri kullanmanız gerekir. DynamicObject'in, özellik listesini herhangi bir yerde gerçekten "saklaması" gerekmez. Örneğin, şöyle bir şey yapabilir ( blog yazımdaki bir örneği yeniden kullanıyorum ):

public class SampleObject : DynamicObject
{
    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        result = binder.Name;
        return true;
    }
}

Bu durumda, bir özelliğe (herhangi bir adla) erişmeye çalıştığınızda, nesne yalnızca özelliğin adını bir dize olarak döndürür.

dynamic obj = new SampleObject();
Console.WriteLine(obj.SampleProperty);
//Prints "SampleProperty".

Yani, üzerinde düşünecek hiçbir şeyiniz yok - bu nesnenin herhangi bir özelliği yoktur ve aynı zamanda tüm geçerli özellik adları çalışacaktır.

IDynamicMetaObjectProvider uygulamaları için, ExpandoObject gibi özelliklerin bir listesini alabileceğiniz ve geri kalanı için yok sayabileceğiniz (veya bir istisna atabileceğiniz) bilinen uygulamaları filtrelemeniz gerektiğini söyleyebilirim.


7
Bana öyle geliyor ki, eğer tükettiğim tür Dinamik ise, o zaman onun altında yatan tür hakkında varsayımlarda bulunmamalıyım. Üye listesini almak için GetDynamicMemberNames'i arayabilmeliyim. Statik türlerin dinamik olanlardan daha iyi çalışma zamanı denetim desteğine sahip olması aptalca görünüyor!
Flatliner DOA

2
Dinamik üyelerin liste adlarını döndürmek üzere dinamik bir nesnenin GetDynamicMemberNames () yöntemini geçersiz kılabilirsiniz. Sorun, her dinamik nesnenin bu yönteme sahip olduğunun garanti edilmemesidir (ExpandoObject yoktur). Statik türler için yansımanın daha iyi çalışması şaşırtıcı değildir. İlk etapta onlar için yaratıldı. Dinamiklerle, birim testine ve TDD'ye daha fazla güvenmelisiniz.
Alexandra Rusina

1
GetDynamicMemberNames () için MSDN Dokümantasyonu şundan bahsediyor: "Bu yöntem yalnızca hata ayıklama amacıyla mevcuttur.", Gerçekten rahatlatıcı değil :(
NicoJuicy

19

Newtonsoft Json.Net gerektirir

Biraz geç, ama bunu buldum. Size sadece anahtarları verir ve sonra bunları dinamikte kullanabilirsiniz:

public List<string> GetPropertyKeysForDynamic(dynamic dynamicToGetPropertiesFor)
{
    JObject attributesAsJObject = dynamicToGetPropertiesFor;
    Dictionary<string, object> values = attributesAsJObject.ToObject<Dictionary<string, object>>();
    List<string> toReturn = new List<string>();
    foreach (string key in values.Keys)
    {
        toReturn.Add(key);                
    }
    return toReturn;
}

O zaman basitçe böyle bir şey yaparsın:

foreach(string propertyName in GetPropertyKeysForDynamic(dynamicToGetPropertiesFor))
{
    dynamic/object/string propertyValue = dynamicToGetPropertiesFor[propertyName];
    // And
    dynamicToGetPropertiesFor[propertyName] = "Your Value"; // Or an object value
}

Değeri bir dize veya başka bir nesne olarak almayı veya başka bir dinamik yapmayı ve aramayı tekrar kullanmayı seçme.


Geri dönmek için listeye ihtiyacınız yok.
aloisdg

4
Mükemmel! JObject niteliklerini değiştirmek zorunda kaldımAsJObject = dynamicToGetPropertiesFor; Nesne özniteliklerineAsJObject = (JObject) JToken.FromObject (obj); rağmen!!
k25

@ K25'in ne dediğini tekrarlamak için. Sen değiştirmeniz gerekiyor JObject attributesAsJObject = dynamicToGetPropertiesFor;gibi bir şey ile: var jObject = (JObject) JToken.FromObject(dynamicToGetPropertiesFor);. Bu noktada, gibi bir şey yaparak mülk adları ve değerlerinin sözlüğünü edinebilirsiniz var objProperties = jObject.ToObject<Dictionary<string, object>>();. Bununla birlikte, yarışlara katılıyorsunuz. Bunun dinamiğe ihtiyacı yok. Alt sınıfı olan her şeyle iyi çalışıyorDynamicObject
Flydog57
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.