javascript では、 undefined キーワードを使用してプロパティが定義されているかどうかを検出できます。
if( typeof data.myProperty == "undefined" ) ...
ExpandoObject
dynamic キーワードを使用し、例外をスローせずに C# でこれを行うにはどうすればよいでしょうか?
javascript では、 undefined キーワードを使用してプロパティが定義されているかどうかを検出できます。
if( typeof data.myProperty == "undefined" ) ...
ExpandoObject
dynamic キーワードを使用し、例外をスローせずに C# でこれを行うにはどうすればよいでしょうか?
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 とは異なり、存在しないプロパティで null をチェックすると、ExpandoObject がスローされます。MVC ViewBag のより穏やかな機能をdynamic
オブジェクトから引き出すには、スローしない 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
、Github で、宣言されていないプロパティの null チェックをスローしない動的オブジェクト ( class ) を次に示します。
https://github.com/b9chris/GracefulDynamicDictionary
NuGet を介してプロジェクトに追加するだけの場合、その名前はGracefulDynamicDictionaryです。
次のようなことができるように、拡張メソッドを作成したかったのです。
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 obj != null && ((IDictionary<String, object>)obj).ContainsKey(propertyName);
}
}
使用するには:
// If the 'MyProperty' property exists...
if (ExpandoObjectHelper.HasProperty(obj, "MyProperty"))
{
...
}
更新: デリゲートを使用して、存在する場合は動的オブジェクト プロパティから値を取得しようとすることができます。プロパティがない場合は、単純に例外をキャッチして 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
最近、非常によく似た質問に答えました。動的オブジェクトのメンバーを反映するにはどうすればよいですか?
まもなく、取得できる動的オブジェクトは ExpandoObject だけではありません。リフレクションは、静的型 (IDynamicMetaObjectProvider を実装しない型) に対して機能します。このインターフェイスを実装する型の場合、リフレクションは基本的に役に立ちません。ExpandoObject の場合、プロパティが基になるディクショナリでキーとして定義されているかどうかを簡単に確認できます。他の実装の場合、それは困難な場合があり、例外を処理することが唯一の方法である場合があります。詳細については、上記のリンクをたどってください。
リフレクションを使用して型プロパティのセットを取得したくないのはなぜですか? このような
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 を未定義と同じと見なすことができる場合は、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
(authorDynamic as ExpandoObject).Any(pair => pair.Key == "YourProp");
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;
}