リフレクションを使用してオブジェクトプロパティを設定する


323

C#でリフレクションを使用してオブジェクトプロパティを設定する方法はありますか?

例:

MyObject obj = new MyObject();
obj.Name = "Value";

obj.Nameリフレクションで設定したい。何かのようなもの:

Reflection.SetProperty(obj, "Name") = "Value";

これを行う方法はありますか?

回答:


391

はい、使用できますType.InvokeMember()

using System.Reflection;
MyObject obj = new MyObject();
obj.GetType().InvokeMember("Name",
    BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty,
    Type.DefaultBinder, obj, "Value");

objというプロパティがない場合Name、または設定できない場合は、例外がスローされます。

別のアプローチは、プロパティのメタデータを取得してから設定することです。これにより、プロパティの存在を確認し、設定できることを確認できます。

using System.Reflection;
MyObject obj = new MyObject();
PropertyInfo prop = obj.GetType().GetProperty("Name", BindingFlags.Public | BindingFlags.Instance);
if(null != prop && prop.CanWrite)
{
    prop.SetValue(obj, "Value", null);
}

73
すべての文字列を処理していない場合は、最初にデータを変換する必要があります。var val = Convert.ChangeType(propValue, propInfo.PropertyType); ソース:devx.com/vb2themax/Tip/19599
LostNomad311

4
または、次を使用することもできますobj.GetType().GetProperty("Name")?.GetSetMethod()?.Invoke(...)
tecfield

1
CanWrite=Falseタイプに値を設定することは不可能ですよね?
T.Todua

287

次のこともできます:

Type type = target.GetType();

PropertyInfo prop = type.GetProperty("propertyName");

prop.SetValue (target, propertyValue, null);

ここで、targetは、プロパティが設定されるオブジェクトです。


11
今日も同じことをやった。上記はうまく機能します。明らかに、使用する前にプロップでnullチェックを行う必要があります。
アントニースコット

3
@AntonyScott間違ったプロパティを呼び出しているかどうかを知りたいと思うので、「サイレントに失敗する」のは悪いコースのようです。
jih 2014年

3
@jih私はあなたのポイントを見ることができますが、それは本当に状況に依存します。
アントニースコット

94

反射、基本的に、すなわち

myObject.GetType().GetProperty(property).SetValue(myObject, "Bob", null);

または、利便性とパフォーマンスの両方の点で役立つライブラリがあります。たとえばFastMemberの場合

var wrapped = ObjectAccessor.Create(obj); 
wrapped[property] = "Bob";

(これは、フィールドかプロパティかを事前に知る必要がないという利点もあります)


うわー、マージで少し混乱しましたが、私はあなたの答えを再び見つけました!ありがとう、あなたは「受け入れる」に値しますが、私のスレッドがマージされているので:(ありがとうございます!
halfpastfour.am

@MarcGravell、私はFastMemberを見ていたが、それはかなり興味深い。私たちの単なる人間があなたのこの素晴らしいlibを使用するための開始/チュートリアルはどこにありますか?
Sudhanshu Mishra 2013

FastMemberでプロパティのタイプを取得するにはどうすればよいですか?
Roohullah Allemによると2014

@Jahanアクセサ=> GetMembers =>メンバー=>タイプ
マークグラベル

すばらしい答えです!oneliner ..自分がどんな意味を成さないかもしれませんためその間には、ユーザーの名前の変数が存在しないので、それは、理解することがはるかに高速であるということです良いところ
Bastiaan

27

または、Marcの1つのライナーを独自の拡張クラスにラップすることもできます。

public static class PropertyExtension{       

   public static void SetPropertyValue(this object obj, string propName, object value)
    {
        obj.GetType().GetProperty(propName).SetValue(obj, value, null);
    }
}

次のように呼び出します:

myObject.SetPropertyValue("myProperty", "myValue");

適切な対策として、プロパティ値を取得するメソッドを追加しましょう。

public static object GetPropertyValue(this object obj, string propName)
{
        return obj.GetType().GetProperty(propName).GetValue (obj, null);
}

14

はい、使用しSystem.Reflectionます:

using System.Reflection;

...

    string prop = "name";
    PropertyInfo pi = myObject.GetType().GetProperty(prop);
    pi.SetValue(myObject, "Bob", null);

13

このようなものを使用してください:

public static class PropertyExtension{       

   public static void SetPropertyValue(this object p_object, string p_propertyName, object value)
   {
    PropertyInfo property = p_object.GetType().GetProperty(p_propertyName);
    property.SetValue(p_object, Convert.ChangeType(value, property.PropertyType), null);
   }
}

または

public static class PropertyExtension{       

   public static void SetPropertyValue(this object p_object, string p_propertyName, object value)
   {
    PropertyInfo property = p_object.GetType().GetProperty(p_propertyName);
    Type t = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType;
    object safeValue = (value == null) ? null : Convert.ChangeType(value, t);

    property.SetValue(p_object, safeValue, null);
   }
}

2
プロパティタイプを取得してキャストする部分は、私にとって非常に役に立ちました。それは魅力のように働きます。ありがとう
Marc

12

類似の方法でフィールドにアクセスすることもできます。

var obj=new MyObject();
FieldInfo fi = obj.GetType().
  GetField("Name", BindingFlags.NonPublic | BindingFlags.Instance);
fi.SetValue(obj,value)

リフレクションを使用すると、すべてを開いた本にすることができます:)私の例では、プライベートインスタンスレベルのフィールドにバインドしています。


8

プロパティ名を使用して別のオブジェクトからオブジェクトのプロパティを一括割り当てする場合は、これを試すことができます。

public static void Assign(this object destination, object source)
    {
        if (destination is IEnumerable && source is IEnumerable)
        {
            var dest_enumerator = (destination as IEnumerable).GetEnumerator();
            var src_enumerator = (source as IEnumerable).GetEnumerator();
            while (dest_enumerator.MoveNext() && src_enumerator.MoveNext())
                dest_enumerator.Current.Assign(src_enumerator.Current);
        }
        else
        {
            var destProperties = destination.GetType().GetProperties();
            foreach (var sourceProperty in source.GetType().GetProperties())
            {
                foreach (var destProperty in destProperties)
                {
                    if (destProperty.Name == sourceProperty.Name && destProperty.PropertyType.IsAssignableFrom(sourceProperty.PropertyType))
                    {
                        destProperty.SetValue(destination,     sourceProperty.GetValue(source, new object[] { }), new object[] { });
                        break;
            }
        }
    }
}

2
こんにちは。StackOverflowへようこそ。コードを適切にフォーマットし、投稿にダンプするだけでなく、他の人があなたの答えを理解するのに役立ちます。
ThreeFx 2014

0

最初のレベルのプロパティだけでなく、指定されたオブジェクトの入れ子になったプロパティも設定できるNugetパッケージを公開しました。

こちらがパッケージです

ルートからのパスによってオブジェクトのプロパティの値を設定します。

オブジェクトは複雑なオブジェクトにすることができ、プロパティはマルチレベルの深いネストされたプロパティにすることも、ルートの直下のプロパティにすることもできます。ObjectWriterプロパティパスパラメータを使用してプロパティを検索し、その値を更新します。プロパティパスは、ルートから設定するエンドノードプロパティにアクセスするプロパティの追加名であり、区切り文字列パラメーターで区切られます。

使用法:

オブジェクトのルートの直下にプロパティを設定するには:

すなわち。LineItemクラスには、呼び出されたintプロパティがありますItemId

LineItem lineItem = new LineItem();

ObjectWriter.Set(lineItem, "ItemId", 13, delimiter: null);

オブジェクトのルートの下にネストされたプロパティの複数のレベルを設定するには:

すなわち。Inviteクラスにはと呼ばれるプロパティがありますState。これにはInvite(Inviteタイプの)と呼ばれるプロパティがありRecipient、にはと呼ばれるプロパティがあり、と呼ばれるプロパティがありますId

物事をさらに複雑にするために、Stateプロパティは参照型ではなく、structです。

以下は、オブジェクトツリーの下部にあるIdプロパティ(「outlook」の文字列値)を1行で設定する方法です。

Invite invite = new Invite();

ObjectWriter.Set(invite, "State_Invite_Recipient_Id", "outlook", delimiter: "_");

0

MarcGravellの提案に基づいて、次の静的メソッドを作成しました。このメソッドは、FastMemberを使用して、ソースオブジェクトからターゲットにすべての一致するプロパティを一般的に割り当てます

 public static void DynamicPropertySet(object source, object target)
    {
        //SOURCE
        var src_accessor = TypeAccessor.Create(source.GetType());
        if (src_accessor == null)
        {
            throw new ApplicationException("Could not create accessor!");
        }
        var src_members = src_accessor.GetMembers();
        if (src_members == null)
        {
            throw new ApplicationException("Could not fetch members!");
        }
        var src_class_members = src_members.Where(x => x.Type.IsClass && !x.Type.IsPrimitive);
        var src_class_propNames = src_class_members.Select(x => x.Name);
        var src_propNames = src_members.Except(src_class_members).Select(x => x.Name);

        //TARGET
        var trg_accessor = TypeAccessor.Create(target.GetType());
        if (trg_accessor == null)
        {
            throw new ApplicationException("Could not create accessor!");
        }
        var trg_members = trg_accessor.GetMembers();
        if (trg_members == null)
        {
            throw new ApplicationException("Could not create accessor!");
        }
        var trg_class_members = trg_members.Where(x => x.Type.IsClass && !x.Type.IsPrimitive);
        var trg_class_propNames = trg_class_members.Select(x => x.Name);
        var trg_propNames = trg_members.Except(trg_class_members).Select(x => x.Name);



        var class_propNames = trg_class_propNames.Intersect(src_class_propNames);
        var propNames = trg_propNames.Intersect(src_propNames);

        foreach (var propName in propNames)
        {
            trg_accessor[target, propName] = src_accessor[source, propName];
        }
        foreach (var member in class_propNames)
        {
            var src = src_accessor[source, member];
            var trg = trg_accessor[target, member];
            if (src != null && trg != null)
            {
                DynamicPropertySet(src, trg);
            }
        }
    }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.