回答:
MSDNによれば、宣言はIDictionaryを実装していることを示しています。
public sealed class ExpandoObject : IDynamicMetaObjectProvider,
IDictionary<string, Object>, ICollection<KeyValuePair<string, Object>>,
IEnumerable<KeyValuePair<string, Object>>, IEnumerable, INotifyPropertyChanged
これを使用して、メンバーが定義されているかどうかを確認できます。
var expandoObject = ...;
if(((IDictionary<String, object>)expandoObject).ContainsKey("SomeMember")) {
// expandoObject.SomeMember exists.
}
ここで重要な区別をする必要があります。
ここでの回答のほとんどは、質問で言及されているExpandoObjectに固有のものです。しかし、ASP.Net MVC ViewBagを使用する場合は、一般的な使用法(および検索時にこの質問に到達する理由)です。これは、DynamicObjectのカスタム実装/サブクラスであり、任意のプロパティ名のnullをチェックしても例外はスローされません。次のようなプロパティを宣言するとします。
@{
ViewBag.EnableThinger = true;
}
次に、その値と、それが設定されているかどうか、つまり存在するかどうかを確認したいとします。以下は有効で、コンパイルされ、例外はスローされず、正しい答えが得られます。
if (ViewBag.EnableThinger != null && ViewBag.EnableThinger)
{
// Do some stuff when EnableThinger is true
}
次に、EnableThingerの宣言を削除します。同じコードが正しくコンパイルおよび実行されます。反射の必要はありません。
ViewBagとは異なり、ExpandoObjectは、存在しないプロパティでnullをチェックするとスローされます。MVC ViewBagのより穏やかな機能をあなたの外に出すためにdynamic
オブジェクトするには、スローしないダイナミックの実装を使用する必要があります。
MVC ViewBagで正確な実装を使用するだけです。
. . .
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で、MVCビューに関連付けられていることがわかります。
http://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/ViewPage.cs
DynamicViewDataDictionaryの正常な動作の鍵は、ViewDataDictionaryでのDictionary実装です。
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
つまり、何が含まれているかに関係なく、常にすべてのキーの値を返します。何もない場合は、単にnullを返します。ただし、ViewDataDictionaryはMVCのモデルに関連付けられているという負担があるため、MVCビューの外部で使用するために、優雅なディクショナリの部分だけを削除することをお勧めします。
すべての根性をここに実際に投稿するには長すぎます-ほとんどはIDictionaryを実装しているだけDDict
ですが、宣言されていないプロパティのnullチェックに対してスローしない動的オブジェクト(クラス)がGithubにあります。
https://github.com/b9chris/GracefulDynamicDictionary
NuGetを介してプロジェクトに追加するだけの場合、その名前はGracefulDynamicDictionaryです。
私は最近、非常によく似た質問に答えました:動的オブジェクトのメンバーをどのように反映するのですか?
簡単に言うと、ExpandoObjectだけが取得できる動的オブジェクトではありません。リフレクションは静的型(IDynamicMetaObjectProviderを実装しない型)で機能します。このインターフェイスを実装する型の場合、リフレクションは基本的に役に立ちません。ExpandoObjectの場合、プロパティが基になるディクショナリのキーとして定義されているかどうかを簡単に確認できます。他の実装では、それは困難な場合があり、例外を処理することが唯一の方法である場合があります。詳細は上記リンク先をご覧ください。
更新:デリゲートを使用して、動的オブジェクトプロパティが存在する場合は、そのプロパティから値を取得しようとすることができます。プロパティがない場合は、例外をキャッチしてfalseを返します。
見てください、私にとってはうまくいきます:
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();
}
コードの出力は次のとおりです。
True
True
False
IsPropertyExist
ます。この例では、をスローできることがわかりますInvalidOperationException
。実際には、どの例外がスローされるかはわかりません。貨物カルトに対抗するために+1。
拡張メソッドを作成して、次のようなことをしたかったのです。
dynamic myDynamicObject;
myDynamicObject.propertyName = "value";
if (myDynamicObject.HasProperty("propertyName"))
{
//...
}
...しかしExpandoObject
、C#5のドキュメント(詳細はこちら)に従って拡張機能を作成することはできません。
だから私はクラスヘルパーを作成することになりました:
public static class ExpandoObjectHelper
{
public static bool HasProperty(ExpandoObject obj, string propertyName)
{
return ((IDictionary<String, object>)obj).ContainsKey(propertyName);
}
}
それを使用するには:
// If the 'MyProperty' property exists...
if (ExpandoObjectHelper.HasProperty(obj, "MyProperty"))
{
...
}
タイププロパティのセットを取得するためにリフレクションを使用したくないのはなぜですか?このような
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
}
この拡張メソッドは、プロパティの存在を確認してから、値またはnullを返します。これは、アプリケーションで不要な例外をスローしたくない場合に役立ちます。少なくとも1つは役立ちます。
public static object Value(this ExpandoObject expando, string name)
{
var expandoDic = (IDictionary<string, object>)expando;
return expandoDic.ContainsKey(name) ? expandoDic[name] : null;
}
そのように使用できる場合:
// lookup is type 'ExpandoObject'
object value = lookup.Value("MyProperty");
または、ローカル変数が「動的」である場合は、最初にそれをExpandoObjectにキャストする必要があります。
// lookup is type 'dynamic'
object value = ((ExpandoObject)lookup).Value("PropertyBeingTested");
ユースケースによっては、nullがundefinedと同じであると見なせる場合は、ExpandoObjectをDynamicJsonObjectに変換できます。
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"));
出力:
a is 1
b is 2.5
c is undefined
みんな、CPUサイクルの負荷が大きいすべての目的でReflectionの使用をやめます。
これが解決策です:
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;
}
}
これを試してください
public bool PropertyExist(object obj, string propertyName)
{
return obj.GetType().GetProperty(propertyName) != null;
}
dynamic
オブジェクトでも機能しません(常にを返しますnull
)。
data.myProperty
。何typeof data.myProperty
が戻るかをチェックします。data.myProperty
存在する可能性があり、に設定されているのは正しいですundefined
が、その場合、typeof
以外の何かが返されます"undefined"
。したがって、このコードは機能します。