文字列を介してC#動的プロパティの値を取得する


182

dynamic文字列でc#プロパティの値にアクセスしたいと思います。

dynamic d = new { value1 = "some", value2 = "random", value3 = "value" };

文字列として「value2」しかない場合、d.value2(「ランダム」)の値を取得するにはどうすればよいですか?JavaScriptでは、d ["value2"]を実行して値(「ランダム」)にアクセスできますが、c#とリフレクションを使用してこれを行う方法がわかりません。私が来た最も近いものはこれです:

d.GetType().GetProperty("value2") ...しかし、そこから実際の値を取得する方法がわかりません。

いつものように、あなたの助けに感謝します!


26
これは「動的」の意図された目的ではなく、このシナリオは「オブジェクト」よりも「動的」でうまく機能しないことに注意してください。「動的」を使用すると、コンパイル時にプロパティの名前がわかっていても、タイプがわからない場合に、プロパティにアクセスできます。コンパイル時に名前も型もわからないので、dynamicは役に立ちません。
Eric Lippert、2011

おそらく関連しています:stackoverflow.com/questions/5877251/…
DuckMaestro 2014年

3
@EricLippert私はこの質問が古いことを知っていますが、誰かが将来それを見た場合に備えてコメントするだけです。場合によっては、動的またはオブジェクトのどちらを使用するか(JSONパーサーを使用する場合など)を選択できず、文字列から(たとえば、構成ファイルから)プロパティを取得したい場合があるため、この使用法はそれほど珍しいことではありません最初は思うかもしれませんが。
ペドロム2017年

回答:


217

あなたが持ってたら、あなたのPropertyInfo(からGetProperty)、あなたが呼び出す必要がありGetValue、あなたがから値を取得したいというインスタンスを渡します。あなたの場合:

d.GetType().GetProperty("value2").GetValue(d, null);

4
私は'd.GetType().GetProperty("value2").GetValue(d)' threw an exception of type 'System.Reflection.TargetInvocationException' dynamic {System.Reflection.TargetInvocationException}それと一緒に時計の窓にいるのです。
TimDog、2011

6
GetValueには追加のパラメータが必要だと思います-egdGetType()。GetProperty( "value2")。GetValue(d、null)
dommer

3
これは匿名型ではなく、真の動的ExpandoObjectで機能しますか?new {}プロパティが定義された実際の匿名型を作成するため、GetType / GetPropertyを呼び出すことは理にかなっていますが、GetTypeを呼び出すと、ExpandoObjectのプロパティを持つ型を取得しますが、その動的プロパティは必ずしも必要ではありません。
Triynko 2014年

16
-1。これは、動的にキャストされた単純な.NETオブジェクトでのみ機能します。ExpandoやViewBagなどのカスタムの動的オブジェクトではASP.NET MVCを使用できません
Philipp Munin

8
これはExpandoオブジェクトで動作するものです:(((IDictionary <string、object>)x))["value1"]
Michael Bahig

39
public static object GetProperty(object target, string name)
{
    var site = System.Runtime.CompilerServices.CallSite<Func<System.Runtime.CompilerServices.CallSite, object, object>>.Create(Microsoft.CSharp.RuntimeBinder.Binder.GetMember(0, name, target.GetType(), new[]{Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(0,null)}));
    return site.Target(site, target);
}

Microsoft.CSharpへの参照を追加します。動的な型とプライベートプロパティおよびフィールドでも機能します。

編集:このアプローチは機能しますが、Microsoft.VisualBasic.dllアセンブリからのメソッドはほぼ20倍高速です。

public static object GetProperty(object target, string name)
{
    return Microsoft.VisualBasic.CompilerServices.Versioned.CallByName(target, name, CallType.Get);
}

2
VisualBasicバージョンが元の 'GetProperty'バージョンと同等ではないことを述べたかっただけです(GetPropertyは実際には動的GetMemberを呼び出し、これはIronPythonのPythonオブジェクトでも機能します)。
Trevor Sundberg、2014年

オブジェクトのターゲットは何でしょうか?
Demodave 2015年

@Demodave(d問題の)プロパティを呼び出すオブジェクト。
IllidanS4はモニカに

➕1これは、FastMemberとHyperDescriptorの両方が機能しないプライベートプロパティで機能しました
Chris Marisic

@ IllidanS4は、CallSiteコードとCallByNameコードを比較したときに、CallSiteインスタンスのキャッシュ中に2つを比較しましたか?私はあなたの最初の方法のコストは、ほぼ純粋の活性化である疑いがあるだろうBinderCallSiteの、ない呼び出しTarget()
クリスMarisic

24

Dynamiteyはオープンソース.net stdライブラリであり、dynamicキーワードのように呼び出すことができますが、コンパイラーが代わりにプロパティ名にa文字列を使用するので、結果的にリフレクション速度と同等になります(これはそれほど高速ではありません)。 dynamicキーワードを使用する場合と同じですが、これは、コンパイラが静的にキャッシュする動的キャッシュのオーバーヘッドが原因です)

Dynamic.InvokeGet(d,"value2");

11

A両方取得する最も簡単な方法settergetterを含む任意のタイプのために働く性質のためdynamic及びExpandoObject使用することですFastMemberも、周りの最速の方法(それはエミットを使用する)であることを起こります。

TypeAccessor特定のタイプに基づいて、または特定のタイプObjectAccessorのインスタンスに基づいて取得できます。

例:

var staticData = new Test { Id = 1, Name = "France" };
var objAccessor = ObjectAccessor.Create(staticData);
objAccessor["Id"].Should().Be(1);
objAccessor["Name"].Should().Be("France");

var anonymous = new { Id = 2, Name = "Hilton" };
objAccessor = ObjectAccessor.Create(anonymous);
objAccessor["Id"].Should().Be(2);
objAccessor["Name"].Should().Be("Hilton");

dynamic expando = new ExpandoObject();
expando.Id = 3;
expando.Name = "Monica";
objAccessor = ObjectAccessor.Create(expando);
objAccessor["Id"].Should().Be(3);
objAccessor["Name"].Should().Be("Monica");

var typeAccessor = TypeAccessor.Create(staticData.GetType());
typeAccessor[staticData, "Id"].Should().Be(1);
typeAccessor[staticData, "Name"].Should().Be("France");

typeAccessor = TypeAccessor.Create(anonymous.GetType());
typeAccessor[anonymous, "Id"].Should().Be(2);
typeAccessor[anonymous, "Name"].Should().Be("Hilton");

typeAccessor = TypeAccessor.Create(expando.GetType());
((int)typeAccessor[expando, "Id"]).Should().Be(3);
((string)typeAccessor[expando, "Name"]).Should().Be("Monica");

8

多くの場合、動的オブジェクトを要求すると、ExpandoObjectを取得します(上の質問の匿名だが静的に型指定された例にはありませんが、JavaScriptと私の選んだJSONパーサーJsonFxの1つがExpandoObjectsを生成します)。

ダイナミックが実際にExpandoObjectである場合、http://msdn.microsoft.com/en-gb/library/system.dynamic.expandoobject.aspxで説明されているように、IDictionaryにキャストすることで反射を回避できます

IDictionaryにキャストすると、.Itemや.ContainsKeyなどの便利なメソッドにアクセスできるようになります。


残念ながら、IDictionaryにキャストして、たとえばTryGetValueを使用すると、プレーンな古いオブジェクトが返されます。暗黙の演算子はコンパイル時にのみ考慮されるため、その時点では暗黙の演算子を利用できません。たとえば、Int64?への暗黙的な変換を行うInt64Proxyクラスがある場合、Int64? i = data.value; //data is ExpandoObject自動的に暗黙的な演算子を検索して呼び出します。一方、「値」フィールドが存在するかどうかをテストするためにIDictionaryを使用する必要がある場合、エラーなくInt64?にキャストされないオブジェクトが返されます。
Triynko 2014年

5

GetProperty / GetValueはJsonデータに対しては機能せず、常にnull例外を生成しますが、このアプローチを試すことができます。

JsonConvertを使用してオブジェクトをシリアル化します。

var z = Newtonsoft.Json.JsonConvert.DeserializeObject(Convert.ToString(request));

次に、アクセスして直接文字列にキャストします。

var pn = (string)z["DynamicFieldName"];

Convert.ToString(request)["DynamicFieldName"]を適用すると、問題なく動作する可能性がありますが、私はテストしていません。


2
このメソッドはエラーを生成します:エラーCS0021:[object]タイプの式に[]を使用したインデックス作成を適用できません。new JavaScriptSerializer().Deserialize<object>(json);あなたが提案した方法で「プロパティ」に到達するために使用します
クリス・キルトン2018

4

d.GetType()。GetProperty( "value2")

PropertyInfoオブジェクトを返します。

それで

propertyInfo.GetValue(d)

2
おかげで、これは正解でしたが、上記のように、GetValue(d)必要がありますGetValue(d,null)
TimDog

4

これは私が動的のプロパティ値の値を取得する方法です:

    public dynamic Post(dynamic value)
    {            
        try
        {
            if (value != null)
            {
                var valorCampos = "";

                foreach (Newtonsoft.Json.Linq.JProperty item in value)
                {
                    if (item.Name == "valorCampo")//property name
                        valorCampos = item.Value.ToString();
                }                                           

            }
        }
        catch (Exception ex)
        {

        }


    }

1

.GetType()返されたときに動的ドキュメントからプロパティを取得するにはnull、次のことを試してください。

var keyValuePairs = ((System.Collections.Generic.IDictionary<string, object>)doc);
var val = keyValuePairs["propertyName"].ToObject<YourModel>;

0

.Net core 3.1では、このように試すことができます

d?.value2 , d?.value3

0

受け入れられた回答と同様に、のGetField代わりに試すこともできますGetProperty

d.GetType().GetField("value2").GetValue(d);

実際のType実装方法によっては、GetProperty()が機能せず、さらに高速である場合に機能する場合があります。


C#3.0+のプロパティとフィールドのFYIの違い:stackoverflow.com/a/653799/2680660
Efreeto
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.