Yanıtlar:
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.
}
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 dynamic
nesnelerinizden çı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;
}
. . .
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 DDict
beyan 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 .
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.
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
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.
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 ExpandoObject
C # 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"))
{
...
}
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 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");
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
(authorDynamic as ExpandoObject).Any(pair => pair.Key == "YourProp");
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;
}
}
Bunu dene
public bool PropertyExist(object obj, string propertyName)
{
return obj.GetType().GetProperty(propertyName) != null;
}
dynamic
(her zaman geri döner null
).
data.myProperty
; Neyintypeof data.myProperty
döndüğünü kontrol eder . Vardata.myProperty
olabileceği ve ayarlanabileceği doğrudurundefined
, ancak bu durumdatypeof
başka bir şey döndürür"undefined"
. Yani bu kod işe yarıyor.