Dize ile c # dynamic özelliğinin değerini alma


182

dynamicBir dize ile bir c # özelliğinin değerine erişmek istiyorum :

dynamic d = new { value1 = "some", value2 = "random", value3 = "value" };

Bir dize olarak yalnızca "value2" varsa d.value2 ("random") değerini nasıl alabilirim? Javascript, ben ("rastgele") değerine erişmek için d ["değer2"] yapabilirdi, ama nasıl c # ve yansıma ile yapmak emin değilim. En yakın geldiğim şudur:

d.GetType().GetProperty("value2") ... ama bundan gerçek değeri nasıl alacağımı bilmiyorum.

Her zaman olduğu gibi, yardımınız için teşekkürler!


26
Bunun "dinamik" in amaçlanan amacı olmadığını ve bu senaryonun "dinamik" ile "nesne" 'den daha iyi çalışmadığını unutmayın. "dynamic" , özellik adı derleme zamanında biliniyor ancak tür bilinmediğinde özelliklere erişmeyi mümkün kılar . Derleme zamanında ne adı ne de türü bildiğiniz için, dinamik size yardımcı olmaz.
Eric Lippert


3
@EricLippert Bu sorunun eski olduğunu biliyorum ama sadece birisinin gelecekte görmesi durumunda yorum yapmak. Bazı durumlarda dinamik mi yoksa nesne mi kullanılacağını seçemezsiniz (örneğin JSON ayrıştırıcısını kullanırken) ve yine de özellikleri bir dizeden (örneğin bir yapılandırma dosyasından) almak isteyebilirsiniz, bu nedenle bu kullanım olağandışı değildir. başlangıçta düşünebileceği gibi.
Pedrom

Yanıtlar:


217

PropertyInfo(From GetProperty) öğenizi aldıktan sonra GetValue, değeri almak istediğiniz örneği çağırmanız ve iletmeniz gerekir . Senin durumunda:

d.GetType().GetProperty("value2").GetValue(d, null);

4
'd.GetType().GetProperty("value2").GetValue(d)' threw an exception of type 'System.Reflection.TargetInvocationException' dynamic {System.Reflection.TargetInvocationException}Saat penceresinden bununla alıyorum ..?
TimDog

6
GetValue'nun ek bir parametreye ihtiyacı olduğunu düşünün - egdGetType (). GetProperty ("value2"). GetValue (d, null)
dommer

3
Bu, anonim bir türden ziyade gerçek bir dinamik ExpandoObject üzerinde çalışır mı? Yana new {}sen GetType ararsanız ExpandoObject, hakkında gerçek anonim GetType / GetProperty mantıklı çağıran tanımlanan özelliklere sahip tipini, ama ne yaratır, değil mutlaka dinamik özelliklerini ExpandoObject özelliklerine sahiptir türü olsun, ama edersiniz.
Triynko

16
-1. Bu yalnızca dinamik olarak yayınlanmış basit .NET nesneleriyle çalışır. ASP.NET MVC kullanılan Expando veya ViewBag gibi herhangi bir özel dinamik nesne ile çalışmaz
Philipp Munin

8
Expando Nesnesi ile çalışan budur: (((IDictionary <string, object>) x)) ["value1"]
Michael Bahig

39
public static object GetProperty(object target, string name)
{
    var site = System.Runtime.CompilerServices.CallSite<Func<System.Runtime.CompilerServices.CallSite, object, object>>.Create(Microsoft.CSharp.RuntimeBinder.Binder.GetMember(0, name, target.GetType(), new[]{Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(0,null)}));
    return site.Target(site, target);
}

Microsoft.CSharp referans ekleyin. Dinamik türler ve özel özellikler ve alanlar için de çalışır.

Düzenleme : Bu yaklaşım çalışırken, Microsoft.VisualBasic.dll derlemesinden neredeyse 20 × daha hızlı yöntem vardır :

public static object GetProperty(object target, string name)
{
    return Microsoft.VisualBasic.CompilerServices.Versioned.CallByName(target, name, CallType.Get);
}

2
VisualBasic sürümünün orijinal 'GetProperty' sürümünüzle eşdeğer olmadığını belirtmek istedim (GetProperty aslında IronPython'daki Python nesnelerinde bile çalışan dinamik GetMember'i çağırır).
Trevor Sundberg

nesne hedefi ne olurdu?
Demodave

@Demodave Özelliği çağırmak istediğiniz nesne ( dsoruda).
IllidanS4, Monica'nın

Fast1 bu hem FastMember hem de HyperDescriptor yapmazsa özel mülkler için çalıştı
Chris Marisic

@ IllidanS4 CallSitekod vs CallByNamekodu karşılaştırdığınızda, CallSiteörneği önbelleğe alırken ikisini karşılaştırdınız mı? Ben senin ilk maliyeti yöntemi neredeyse tamamen aktivasyonu şüpheli olur Binderve CallSite, değil çağırma aitTarget()
Chris Marisic

24

Dynamitey , anahtar kelime .net stdgibi çağırmanıza izin veren açık kaynaklı bir kitaplıktır, dynamicancak bunu sizin için yapan derleyici yerine özellik adı için bir dize kullanarak ve hızlı bir şekilde yansımaya eşit olur (bu neredeyse hızlı değildir) dinamik anahtar kelimeyi kullandığınızda, ancak bunun nedeni derleyicinin statik olarak önbelleğe aldığı dinamik olarak önbelleğe almanın fazladan yüküdür).

Dynamic.InvokeGet(d,"value2");

11

A hem elde etmek için en kolay yöntem setterve getterdahil herhangi bir tür için çalışan bir özellik için dynamicve ExpandoObjectkullanım etmektir FastMemberda (o yayarlar kullanır) en hızlı yöntem etrafta olur.

Ya bir alabilirsiniz TypeAccessorbelirli bir türü veya bir dayalı ObjectAccessorbelirli bir türden bir örneğinin dayalı.

Misal:

var staticData = new Test { Id = 1, Name = "France" };
var objAccessor = ObjectAccessor.Create(staticData);
objAccessor["Id"].Should().Be(1);
objAccessor["Name"].Should().Be("France");

var anonymous = new { Id = 2, Name = "Hilton" };
objAccessor = ObjectAccessor.Create(anonymous);
objAccessor["Id"].Should().Be(2);
objAccessor["Name"].Should().Be("Hilton");

dynamic expando = new ExpandoObject();
expando.Id = 3;
expando.Name = "Monica";
objAccessor = ObjectAccessor.Create(expando);
objAccessor["Id"].Should().Be(3);
objAccessor["Name"].Should().Be("Monica");

var typeAccessor = TypeAccessor.Create(staticData.GetType());
typeAccessor[staticData, "Id"].Should().Be(1);
typeAccessor[staticData, "Name"].Should().Be("France");

typeAccessor = TypeAccessor.Create(anonymous.GetType());
typeAccessor[anonymous, "Id"].Should().Be(2);
typeAccessor[anonymous, "Name"].Should().Be("Hilton");

typeAccessor = TypeAccessor.Create(expando.GetType());
((int)typeAccessor[expando, "Id"]).Should().Be(3);
((string)typeAccessor[expando, "Name"]).Should().Be("Monica");

8

Dinamik bir nesne istediğinizde çoğu zaman bir ExpandoObject elde edersiniz (yukarıdaki sorunun anonim ama statik olarak yazılan örneğinde değil, ancak JavaScript ve seçtiğim JSON ayrıştırıcı JsonFx'ten bir tanesi ExpandoObjects oluşturur).

Dinamikiniz aslında bir ExpandoObject ise, http://msdn.microsoft.com/en-gb/library/system.dynamic.expandoobject.aspx adresinde açıklanan şekilde IDictionary'e yansıtarak yansımayı önleyebilirsiniz .

IDictionary'e yayın yaptıktan sonra, .Item ve .ContainsKey gibi yararlı yöntemlere erişebilirsiniz.


Ne yazık ki, IDictionary'e yayın yapmak ve örneğin TryGetValue kullanmak, eski düz bir nesnenin döndürülmesiyle sonuçlanır. Bu noktada örtülü işleçlerden yararlanamazsınız, çünkü yalnızca derleme zamanında dikkate alınırlar. Örneğin, ben Int64 için örtük dönüştürme ile bir Int64Proxy sınıfı vardı, o Int64? i = data.value; //data is ExpandoObjectzaman otomatik olarak arama ve örtük işleci çağırır. Öte yandan, eğer "değer" alanının olup olmadığını test etmek için IDictionary kullanmak zorunda olsaydım, Int64?
Triynko

5

GetProperty / GetValue Json verileri için çalışmaz, her zaman boş bir istisna oluşturur, ancak bu yaklaşımı deneyebilirsiniz:

JsonConvert kullanarak nesnenizi seri hale getirin:

var z = Newtonsoft.Json.JsonConvert.DeserializeObject(Convert.ToString(request));

Ardından doğrudan dizeye geri yayınlayarak erişin:

var pn = (string)z["DynamicFieldName"];

Ancak ben test etmedim Convert.ToString (istek) ["DynamicFieldName"] uygulayarak düz çalışabilir.


2
Bu yöntem hatayı oluşturur: hata CS0021: 'object' türündeki bir ifadeye [] ile dizinleme uygulanamıyor. new JavaScriptSerializer().Deserialize<object>(json);Önerdiğiniz şekilde "mülklere" ulaşmak için kullanın
Kris Kilton

4

d.GetType (). GetProperty ( "deger2")

bir PropertyInfo nesnesi döndürür.

Öyleyse yap

propertyInfo.GetValue(d)

2
teşekkürler, bu doğru cevaptı, ama yukarıda belirtildiği gibi GetValue(d)olması gerekiyorGetValue(d,null)
TimDog

4

Bu bir dinamik özellik değeri değeri var ve yoludur:

    public dynamic Post(dynamic value)
    {            
        try
        {
            if (value != null)
            {
                var valorCampos = "";

                foreach (Newtonsoft.Json.Linq.JProperty item in value)
                {
                    if (item.Name == "valorCampo")//property name
                        valorCampos = item.Value.ToString();
                }                                           

            }
        }
        catch (Exception ex)
        {

        }


    }

1

Ne zaman dinamik dokümandan özelliklerini almak için .GetType()geri döner null, bu deneyin:

var keyValuePairs = ((System.Collections.Generic.IDictionary<string, object>)doc);
var val = keyValuePairs["propertyName"].ToObject<YourModel>;

0

Net core 3.1'de bunu deneyebilirsiniz

d?.value2 , d?.value3

0

Kabul edilen cevaba benzer şekilde GetFieldbunun yerine deneyebilirsiniz GetProperty.

d.GetType().GetField("value2").GetValue(d);

Gerçek Typeuygulamanın nasıl uygulandığına bağlı olarak, GetProperty () çalışmadığında ve hatta daha hızlı olabildiğinde bu işe yarayabilir.


C # 3.0+'daki Özellik ve Alan arasındaki FYI Farkı: stackoverflow.com/a/653799/2680660
Efreeto
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.