ExpandoObject üzerinde bir özellik olup olmadığını nasıl tespit edebilirim?


188

Javascript'te, bir özelliğin tanımlanıp tanımlanmadığını anahtar sözcük kullanarak tanımlayabilirsiniz:

if( typeof data.myProperty == "undefined" ) ...

ExpandoObjectİstisna atmadan ve ile dinamik anahtar kelimeyi kullanarak C # 'da bunu nasıl yaparsınız ?


5
@CodeInChaos: Görüntülenen kodun data.myProperty; Neyin typeof data.myPropertydöndüğünü kontrol eder . Var data.myPropertyolabileceği ve ayarlanabileceği doğrudur undefined, ancak bu durumda typeofbaşka bir şey döndürür "undefined". Yani bu kod işe yarıyor.
Aasmund Eldhuset

Yanıtlar:


181

Göre MSDN o IDictionary uyguluyor beyan gösterileri:

public sealed class ExpandoObject : IDynamicMetaObjectProvider, 
    IDictionary<string, Object>, ICollection<KeyValuePair<string, Object>>, 
    IEnumerable<KeyValuePair<string, Object>>, IEnumerable, INotifyPropertyChanged

Bir üyenin tanımlanıp tanımlanmadığını görmek için bunu kullanabilirsiniz:

var expandoObject = ...;
if(((IDictionary<String, object>)expandoObject).ContainsKey("SomeMember")) {
    // expandoObject.SomeMember exists.
}

3
Bu kontrolü daha basit hale getirmek için TryGetValue'yi aşırı yükledim ve özellik tanımlanmadıysa dönüş değerini "undefined" olarak ayarlayarak her zaman true değerini döndürdüm. if (someObject.someParam! = "undefined") ... Ve işe yarıyor :)
Softlion

Ayrıca mümkün :), ama bence aşırı yüklenmiş yerine "geçersiz kılınmış" demek istedim.
Dykam

Evet. Yine başka bir yerde oluşturulmuş özel bir nesnenin const değeri "tanımsız" değiştirdim. Döküm problemlerini önler: p
Softlion

1
Bu çözümün hala güncel olduğuna inanıyorum; Yansımanın fiyatı için kimsenin sözünü
tutmayın

1
@ BlueRaja-DannyPflughoeft Evet, öyle. Oyuncular olmadan, iç kısımlara girdiğinizde dinamik bir çağrı olacaktır. Daha spesifik olarak, açıkça uygulanır: github.com/mono/mono/blob/master/mcs/class/dlr/Runtime/…
Dykam

28

Burada önemli bir ayrım yapılması gerekiyor.

Buradaki cevapların çoğu, soruda belirtilen ExpandoObject'e özgüdür. Ancak ASP.Net MVC ViewBag kullanıldığında yaygın bir kullanım (ve arama yaparken bu soruya inmenin nedeni). Bu, null için herhangi bir rastgele özellik adını kontrol ettiğinizde İstisna atmayacak bir DynamicObject özel uygulaması / alt sınıfıdır. Aşağıdaki gibi bir mülk beyan edebileceğinizi varsayalım:

@{
    ViewBag.EnableThinger = true;
}

Ardından, değerini ve hatta ayarlanıp ayarlanmadığını kontrol etmek istediğinizi varsayalım. Aşağıdakiler geçerlidir, derlenir, istisnalar atmaz ve size doğru cevabı verir:

if (ViewBag.EnableThinger != null && ViewBag.EnableThinger)
{
    // Do some stuff when EnableThinger is true
}

Şimdi EnableThinger'ın deklarasyonundan kurtulun. Aynı kod düzgün bir şekilde derlenir ve çalışır. Yansıtmaya gerek yok.

ViewBag'den farklı olarak, var olmayan bir mülkte null olup olmadığını kontrol ederseniz ExpandoObject atılacaktır. MVC ViewBag'in yumuşak işlevselliğini dynamicnesnelerinizden çıkarmak için, atmayan bir dinamik uygulaması kullanmanız gerekir.

MVC ViewBag'de tam uygulamayı kullanabilirsiniz:

. . .
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
    result = ViewData[binder.Name];
    // since ViewDataDictionary always returns a result even if the key does not exist, always return true
    return true;
}
. . .

https://github.com/ASP-NET-MVC/aspnetwebstack/blob/master/src/System.Web.Mvc/DynamicViewDataDictionary.cs

MVC ViewPage'de MVC Görünümlerine bağlı olduğunu görebilirsiniz:

http://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/ViewPage.cs

DynamicViewDataDictionary zarif davranışının anahtarı burada ViewDataDictionary üzerinde Sözlük uygulamasıdır:

public object this[string key]
{
    get
    {
        object value;
        _innerDictionary.TryGetValue(key, out value);
        return value;
    }
    set { _innerDictionary[key] = value; }
}

https://github.com/ASP-NET-MVC/aspnetwebstack/blob/master/src/System.Web.Mvc/ViewDataDictionary.cs

Başka bir deyişle, içinde ne olursa olsun, tüm anahtarlar için her zaman bir değer döndürür - orada hiçbir şey olmadığında sadece null değerini döndürür. Ancak, ViewDataDictionary MVC Modeline bağlı olma yükü vardır, bu nedenle MVC Görünümleri dışında kullanmak için sadece zarif sözlük parçalarını çıkarmak daha iyidir.

Burada tüm bağırsakları gerçekten yayınlamak çok uzun - çoğu sadece IDictionary uyguluyor - ancak Github'da DDictbeyan edilmemiş mülklerde boş kontroller yapmayan dinamik bir nesne (sınıf ):

https://github.com/b9chris/GracefulDynamicDictionary

NuGet aracılığıyla projenize eklemek istiyorsanız, adı GracefulDynamicDictionary .


O zaman neden yansıma kullanmadığı için DynamicDictionary'a oy verdiniz?
Softlion

aynı çözüm olduğu için oy verebilirsiniz :)
Softlion

3
Kesinlikle aynı çözüm değildir.
Chris Moschini

"bir özellik bulunmadığında atmayan benzer bir alt sınıf oluşturmanız gerekir." => öyle! Oh hayır değil. Benim çözümüm daha iyi. Atar - çünkü istiyoruz, ve TryXX kullanılıyorsa da atamaz;
Softlion

1
BU, BU tam olarak neden buradayım, neden bazı kod (viewbag) kırılma DEĞİL anlayamadık. Teşekkür ederim.
Adam Tolley

11

Son zamanlarda çok benzer bir soruyu cevapladım: Dinamik nesnenin üyelerini nasıl yansıtabilirim?

Kısacası, ExpandoObject alabileceğiniz tek dinamik nesne değildir. Yansıma, statik türler (IDynamicMetaObjectProvider uygulamayan türler) için çalışır. Bu arabirimi uygulayan türler için yansıma temelde işe yaramaz. ExpandoObject için, özelliğin temel sözlükte bir anahtar olarak tanımlanıp tanımlanmadığını kontrol edebilirsiniz. Diğer uygulamalar için zor olabilir ve bazen tek yol istisnalarla çalışmaktır. Ayrıntılar için yukarıdaki bağlantıyı takip edin.


11

GÜNCELLENDİ: Temsilciler kullanabilir ve varsa dinamik nesne özelliğinden bir değer almaya çalışabilirsiniz. Özellik yoksa, istisnayı yakalayın ve false değerini döndürün.

Bir bak, benim için iyi çalışıyor:

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

        Console.WriteLine(IsPropertyExist(() => userDynamic.first_name));
        Console.WriteLine(IsPropertyExist(() => userDynamic.address));
        Console.WriteLine(IsPropertyExist(() => userDynamic.last_name));
    }

    class JsonUser
    {
        public string first_name { get; set; }
        public string address
        {
            get
            {
                throw new InvalidOperationException("Cannot read property value");
            }
        }
    }

    static bool IsPropertyExist(GetValueDelegate getValueMethod)
    {
        try
        {
            //we're not interesting in the return value. What we need to know is whether an exception occurred or not
            getValueMethod();
            return true;
        }
        catch (RuntimeBinderException)
        {
            // RuntimeBinderException occurred during accessing the property
            // and it means there is no such property         
            return false;
        }
        catch
        {
            //property exists, but an exception occurred during getting of a value
            return true;
        }
    }

    delegate string GetValueDelegate();
}

Kodun çıktısı şudur:

True
True
False

2
@marklam İstisnaya neyin sebep olduğunu bilmiyorsanız tüm istisnayı yakalamak kötüdür. Bizim durumumuzda, bir alanın bulunmamasını beklediğimiz için sorun yok.
Alexander G

3
İstisnaya neyin sebep olduğunu biliyorsanız, türünü de bilmelisiniz, bu yüzden catch (WhateverException) Aksi takdirde, örneğin OutOfMemoryException gibi beklenmedik bir istisna olsa bile kodunuz sessizce devam edecektir.
marklam

4
Herhangi bir alıcıya geçebilirsiniz IsPropertyExist. Bu örnekte, bilirsiniz, bir InvalidOperationException. Uygulamada, hangi istisnanın atılabileceği hakkında hiçbir fikriniz yoktur. Kargo kültüne karşı koymak için +1.
Piedar

2
Performans önemliyse bu çözüm kabul edilemez, örneğin 500+ yinelemeli bir döngüde kullanılırsa eklenir ve birkaç saniye gecikmeye neden olabilir. Her istisna yakalandığında yığın, istisna nesnesine kopyalanmalıdır
Jim109

1
Ynt: Performans: Bağlanan hata ayıklayıcı ve Console.WriteLine yavaş bitlerdir. 10.000 yineleme burada 200 ms'den az sürer (yineleme başına 2 istisna hariç). İstisnasız aynı test bir avuç milisaniye sürer. Bu, bu kodu kullanımınızın yalnızca nadiren bir mülkü kaçırmasını bekliyorsanız veya sınırlı sayıda kez çağırıyorsanız veya sonuçları önbelleğe alabiliyorsanız, lütfen her şeyin yerini ve aşırı bir şeyin olmadığını unutmayın. -Burada düzenlenmiş uyarılar önemlidir.
Kaos

10

Ben böyle bir şey yapabilmek için bir uzantı yöntemi oluşturmak istedim :

dynamic myDynamicObject;
myDynamicObject.propertyName = "value";

if (myDynamicObject.HasProperty("propertyName"))
{
    //...
}

... ancak ExpandoObjectC # 5 belgelerine göre uzantı oluşturamazsınız (daha fazla bilgi burada ).

Böylece bir sınıf yardımcısı oluşturdum:

public static class ExpandoObjectHelper
{
    public static bool HasProperty(ExpandoObject obj, string propertyName)
    {
        return ((IDictionary<String, object>)obj).ContainsKey(propertyName);
    }
}

Kullanmak için:

// If the 'MyProperty' property exists...
if (ExpandoObjectHelper.HasProperty(obj, "MyProperty"))
{
    ...
}

4
yararlı yorum için oy ve ExpandoObject uzantıları için bağlantı.
Roberto

1

Neden tür özellikleri ayarlamak için Yansıma kullanmak istemiyorsunuz? Bunun gibi

 dynamic v = new Foo();
 Type t = v.GetType();
 System.Reflection.PropertyInfo[] pInfo =  t.GetProperties();
 if (Array.Find<System.Reflection.PropertyInfo>(pInfo, p => { return p.Name == "PropName"; }).    GetValue(v,  null) != null))
 {
     //PropName initialized
 } 

Bu dinamik olarak eklenen özellikleri döndürecek emin değilim, benim tahminim Dinamik nesnenin yöntemlerini döndürür.
Dykam

1

Bu uzantı yöntemi, bir özelliğin varlığını denetler ve sonra değeri veya null değerini döndürür. Bu, uygulamalarınızın en azından yardımcı olabileceğiniz gereksiz istisnalar atmasını istemiyorsanız kullanışlıdır.

    public static object Value(this ExpandoObject expando, string name)
    {
        var expandoDic = (IDictionary<string, object>)expando;
        return expandoDic.ContainsKey(name) ? expandoDic[name] : null;
    }

Bu şekilde kullanılabilirse:

  // lookup is type 'ExpandoObject'
  object value = lookup.Value("MyProperty");

veya yerel değişkeniniz 'dinamik' ise öncelikle ExpandoObject öğesine yayınlamanız gerekir.

  // lookup is type 'dynamic'
  object value = ((ExpandoObject)lookup).Value("PropertyBeingTested");

1

Kullanım durumunuza bağlı olarak, null undefined ile aynı kabul edilebilirse, ExpandoObject öğenizi DynamicJsonObject'e dönüştürebilirsiniz.

    dynamic x = new System.Web.Helpers.DynamicJsonObject(new ExpandoObject());
    x.a = 1;
    x.b = 2.50;
    Console.WriteLine("a is " + (x.a ?? "undefined"));
    Console.WriteLine("b is " + (x.b ?? "undefined"));
    Console.WriteLine("c is " + (x.c ?? "undefined"));

Çıktı:

a is 1
b is 2.5
c is undefined

-2
(authorDynamic as ExpandoObject).Any(pair => pair.Key == "YourProp");

-3

Hey millet, çok fazla CPU döngüsüne mal olan her şey için Reflection'ı kullanmayı bırakıyor.

İşte çözüm:

public class DynamicDictionary : DynamicObject
{
    Dictionary<string, object> dictionary = new Dictionary<string, object>();

    public int Count
    {
        get
        {
            return dictionary.Count;
        }
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        string name = binder.Name;

        if (!dictionary.TryGetValue(binder.Name, out result))
            result = "undefined";

        return true;
    }

    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        dictionary[binder.Name] = value;
        return true;
    }
}

4
Bu, bir nesnenin dinamik bir nesnede çıktığını nasıl göreceğinizi değil, dinamik bir nesnenin nasıl uygulanacağını gösterir.
Matt Warren

Söz konusu mülke karşı bir boş kontrol yaparak dinamik bir örneğin bir özelliğe sahip olup olmadığını kontrol edebilirsiniz.
ctorx

2
“Bu dinamik bir nesnenin nasıl uygulanacağını gösterir”: evet aslında öyle. Bu sorunun çözümü: uygulamaya bağlı olduğu için genel bir çözüm yoktur.
Softlion

@Softlion Hayır, çözüm, kullanmayı
bırakmamız

@Softlion Tryxxx yöntemlerinin anlamı nedir? TryGet özelliği bulamadığında asla false değerini döndürmez, bu nedenle yine de sonucu kontrol etmeniz gerekir. Dönüş işe yaramaz. TrySet'te anahtar yoksa, false döndürmek yerine bir istisna atar. Bunu neden bir cevap olarak kullanacağınızı anlamıyorum, eğer siz de burada "Bu sorunun çözümü: uygulamaya bağlı olarak jenerik bir çözüm yoktur" yazdıysanız, bu da doğru değildir. Gerçek çözüm için Dykam'ın cevabına bakın.
pqsk

-5

Bunu dene

public bool PropertyExist(object obj, string propertyName)
{
 return obj.GetType().GetProperty(propertyName) != null;
}

3
Bu, dinamik ad altında gizlenen bir nesnenin, bir uygulama ayrıntısı olan varlığının varlığını kontrol eder. Göndermeden önce çözümünüzü gerçek kodla doğruladınız mı? Hiç çalışmamalı.
Softlion

Bu kod parçasını gerçek zamanlı senaryoda kullandım. İyi çalışıyor.
Venkat

6
Mülkiyet mevcut olsa bile bana her zaman boş verir.
atlantis

Temel nesnelerle çalışır, ancak ExpandoObjects ile çalışmaz. Dinamik, emin değilim.
Joe

1
Onaylamak için, bu nesnelerle de çalışmaz dynamic(her zaman geri döner null).
Gitti Kodlama
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.