動的オブジェクトのメンバーを反映​​するにはどうすればよいですか?


131

.NET 4の動的キーワードで宣言されたオブジェクトからプロパティとその値の辞書を取得する必要がありますか?これにリフレクションを使用しても機能しないようです。

例:

dynamic s = new ExpandoObject();
s.Path = "/Home";
s.Name = "Home";

// How do I enumerate the Path and Name properties and get their values?
IDictionary<string, object> propertyValues = ???

回答:


32

IDynamicMetaObjectProviderが動的メンバー名を提供できる場合、それらを取得できます。ApacheライセンスのPCLライブラリDynamiteynugetにあります)のGetMemberNames実装を参照してください。これは、実装するsおよびs と、カスタムテスト以外の実装を持つメタオブジェクトを実装する他の人に対して機能します。ExpandoObjectDynamicObjectGetDynamicMemberNamesIDynamicMetaObjectProviderGetDynamicMemberNamesis IDynamicMetaObjectProvider

メンバー名を取得した後、正しい方法で値を取得するのは少し手間がかかりますが、Impromptuはこれを行いますが、興味深い部分だけを指摘して意味をなすことは困難です。ここだドキュメントと、それは、しかし、そうは速くはExpandoのための辞書検索よりも速くする反射よりも等しいか、それは任意のオブジェクト、Expandoで、動的またはオリジナルの作品-あなたはそれに名前を付けます。


17
ポイントに到達していただきありがとうございます。コードは次のとおりです。var tTarget = target as IDynamicMetaObjectProvider; if(tTarget!= null){tList.AddRange(tTarget.GetMetaObject(Expression.Constant(tTarget))。GetDynamicMemberNames()); }
Flatliner DOA 2013

素晴らしいライブラリをありがとう。動的オブジェクトをこのライブラリdynamicjson.codeplex.comにラウンドトリップする際に問題が発生し、ライブラリでそれを拡張することができました。
JJS 2016

1
例をご覧ください。
Demodave 2017年

105

ExpandoObjectの場合、ExpandoObjectクラスは実際IDictionary<string, object>にそのプロパティを実装するため、解決策はキャストと同じくらい簡単です。

IDictionary<string, object> propertyValues = (IDictionary<string, object>)s;

これは一般的な動的オブジェクトでは機能しないことに注意してください。これらの場合、IDynamicMetaObjectProviderを介してDLRにドロップダウンする必要があります。


そのおかげで、残念ながらサンプルは少し単純化しすぎていました。実際のタイプが何であるかを知らなくても、動的オブジェクトを検査できる必要があります。
Flatliner DOA 2010

2
これはExpandoObjectクラスのオブジェクトに対してのみ機能します。DynamicObjectクラスは、IDictionaryを実装せず、IDynamicMetaObjectProviderを実装する別の拡張可能なクラスです。
Sharique Abdullah 2017

1
OPの質問にも答えます。
Sharique Abdullah 2017

58

考慮すべきシナリオがいくつかあります。まず、オブジェクトのタイプを確認する必要があります。このためには、GetType()を呼び出すだけです。型がIDynamicMetaObjectProviderを実装していない場合は、他のオブジェクトと同じようにリフレクションを使用できます。何かのようなもの:

var propertyInfo = test.GetType().GetProperties();

ただし、IDynamicMetaObjectProvider実装の場合、単純なリフレクションは機能しません。基本的に、あなたはこのオブジェクトについてもっと知る必要があります。それがExpandoObject(IDynamicMetaObjectProvider実装の1つ)の場合は、itowlsonによって提供される回答を使用できます。ExpandoObjectはそのプロパティをディクショナリに格納し、動的オブジェクトをディクショナリにキャストするだけです。

DynamicObject(別のIDynamicMetaObjectProvider実装)の場合、このDynamicObjectが公開するメソッドを使用する必要があります。DynamicObjectは、プロパティのリストをどこかに実際に「保存」する必要はありません。たとえば、次のようなことが行われる場合があります(ブログの投稿の例を再利用しています)。

public class SampleObject : DynamicObject
{
    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        result = binder.Name;
        return true;
    }
}

この場合、任意の名前でプロパティにアクセスしようとすると、オブジェクトはプロパティの名前を文字列として返すだけです。

dynamic obj = new SampleObject();
Console.WriteLine(obj.SampleProperty);
//Prints "SampleProperty".

したがって、反映するものは何もありません。このオブジェクトにはプロパティがなく、同時にすべての有効なプロパティ名が機能します。

IDynamicMetaObjectProvider実装の場合、ExpandoObjectなどのプロパティのリストを取得できる既知の実装でフィルタリングし、残りの部分は無視(または例外をスロー)する必要があります。


7
私が消費する型が動的である場合、その基礎となる型について仮定するべきではないように思えます。GetDynamicMemberNamesを呼び出してメンバーのリストを取得できるはずです。静的型の方が動的型よりも実行時検査のサポートが優れているのは愚かです!
Flatliner DOA

2
動的オブジェクトのGetDynamicMemberNames()メソッドをオーバーライドして、動的メンバーのリスト名を返すことができます。問題は、すべての動的オブジェクトがこのメソッドを持っていることが保証されていないことです(ExpandoObjectにはありません)。静的型のほうがリフレクションがうまく機能するのは当然のことです。そもそも彼らのために作られました。ダイナミクスでは、ユニットテストとTDDにさらに依存する必要があります。
Alexandra

1
GetDynamicMemberNames()のMSDNドキュメントには、「このメソッドはデバッグ目的でのみ存在します。」と記載されており、あまり快適ではありません:(
NicoJuicy

19

Newtonsoft Json.Netが必要

少し遅れましたが、これは思いつきました。それはあなたにただキーを与え、そしてあなたはダイナミックでそれらを使うことができます:

public List<string> GetPropertyKeysForDynamic(dynamic dynamicToGetPropertiesFor)
{
    JObject attributesAsJObject = dynamicToGetPropertiesFor;
    Dictionary<string, object> values = attributesAsJObject.ToObject<Dictionary<string, object>>();
    List<string> toReturn = new List<string>();
    foreach (string key in values.Keys)
    {
        toReturn.Add(key);                
    }
    return toReturn;
}

次に、単に次のようにforeachします。

foreach(string propertyName in GetPropertyKeysForDynamic(dynamicToGetPropertiesFor))
{
    dynamic/object/string propertyValue = dynamicToGetPropertiesFor[propertyName];
    // And
    dynamicToGetPropertiesFor[propertyName] = "Your Value"; // Or an object value
}

値を文字列またはその他のオブジェクトとして取得するか、別のダイナミックを実行してルックアップを再度使用するかを選択します。


リストを返す必要はありません。
aloisdgがcodidact.comに移動2016年

4
パーフェクト!JObject attributesAsJObject = dynamicToGetPropertiesFor;を変更する必要がありました。オブジェクトへの属性AsJObject =(JObject)JToken.FromObject(obj); でも!!
k25

@ k25の発言を繰り返します。JObject attributesAsJObject = dynamicToGetPropertiesFor;次のようなものに置き換える必要がありますvar jObject = (JObject) JToken.FromObject(dynamicToGetPropertiesFor);。その時点で、のようなことを行うことにより、プロパティの名前と値の辞書を取得できますvar objProperties = jObject.ToObject<Dictionary<string, object>>();。これで、あなたはレースに出かけます。これはダイナミックを必要としません。これは、サブクラスのあるもので罰金に動作しますDynamicObject
Flydog57
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.