web-dev-qa-db-ja.com

オブジェクトプロパティに文字列としてアクセスし、その値を設定する

Accountクラスのインスタンスがあります。各アカウントオブジェクトには、所有者、参照などがあります。

アカウントのプロパティにアクセスする1つの方法は、

account.Reference;

しかし、私は次のような動的な文字列セレクタを使用してそれにアクセスできるようにしたいと思います:

account["PropertyName"];

javaScriptのように。だから私はaccount["Reference"]これは値を返しますが、その後に次のように新しい値を割り当てることもできます。

account["Reference"] = "124ds4EE2s";

使えることに気づいた

DataBinder.Eval(account,"Reference") 

文字列に基づいてプロパティを取得しますが、これを使用してプロパティに値を割り当てることはできません。

どうすればそれができるのか?

43
zanona

まず、これを使用しないでください。 C#は強く型付けされた言語なので、その側面に伴う型の安全性とパフォーマンスの利点を活用してください。

プロパティの値を動的に取得および設定する正当な理由がある場合(つまり、タイプやプロパティ名をコードで定義できない場合)、リフレクションを使用する必要があります。

最もインラインに見える方法はこれでしょう:

object value = typeof(YourType).GetProperty("PropertyName").GetValue(yourInstance);
...
typeof(YourType).GetProperty("PropertyName").SetValue(yourInstance, "value");

ただし、PropertyInfoオブジェクトをキャッシュして読みやすくすることができます。

System.Reflection.PropertyInfo prop = typeof(YourType).GetProperty("PropertyName");

object value = prop.GetValue(yourInstance);
...
prop.SetValue(yourInstance, "value");
66
Adam Robinson

インデクサーとリフレクションを組み合わせてみてください...

public object this[string propertyName]
{
    get
    {
        PropertyInfo property = GetType().GetProperty(propertyName);
        return property.GetValue(this, null);
    }
    set
    {
        PropertyInfo property = GetType().GetProperty(propertyName);
        property.SetValue(this,value, null);
    }
}
32
Richard Friend

.Net 4を使用している場合、今すぐdynamicキーワードを使用できます。

dynamic foo = account;
foo.Reference = "124ds4EE2s";
6
Rob Sedgwick

Richardのリフレクションメソッドを使用しましたが、文字列やnullなど、使用されている他の型を処理するためにsetメソッドを作成しました。

public object this[string propertyName]
{
    get
    {
        PropertyInfo property = GetType().GetProperty(propertyName);
        return property.GetValue(this, null);
    }
    set
    {
        PropertyInfo property = GetType().GetProperty(propertyName);
        Type propType = property.PropertyType;
        if (value == null)
        {
            if (propType.IsValueType && Nullable.GetUnderlyingType(propType) == null)
            {
                throw new InvalidCastException();
            }
            else
            {
                property.SetValue(this, null, null);
            }
        }
        else if (value.GetType() == propType)
        {
            property.SetValue(this, value, null);
        }
        else
        {
            TypeConverter typeConverter = TypeDescriptor.GetConverter(propType);
            object propValue = typeConverter.ConvertFromString(value.ToString());
            property.SetValue(this, propValue, null);
        }
    }
}

変換が機能しない場合、SetValue()関数はエラーをスローします。

6
Ken Mc

独自のオブジェクトである場合、フィールドにアクセスするためのインデクサーを提供できます。私はこれを本当にお勧めしませんが、あなたが望むものを可能にします。

public object this[string propertyName]
{
    get
    {
        if(propertyName == "Reference")
            return this.Reference;
        else
            return null;
    }
    set
    {
        if(propertyName == "Reference")
            this.Reference = value;
        else
            // do error case here            
    }
}

これを行うと、タイプセーフが失われることに注意してください。

6
Stephan

私は個人的に拡張メソッドで作業することを好むので、ここに私のコードがあります:

public static class ReflectionExtensions
{
    public static void SetPropertyValue(this object Target,
        string PropertyName,
        object NewValue)
    {
        if (Target == null) return; //or throw exception

        System.Reflection.PropertyInfo prop = Target.GetType().GetProperty(PropertyName);

        if (prop == null) return; //or throw exception

        object value = prop.GetValue(Target, null);

        prop.SetValue(Target, NewValue, null);
    }
}
2
Stefan Michev

おそらくあなたはプロパティを使用する必要があるという以前のポスターに同意します。反射は、プロパティへの直接アクセスと比較して非常に遅いです。

一方、ユーザー定義プロパティのリストを維持する必要がある場合、C#プロパティを使用できません。自分がDictionaryであるふりをするか、Dictionaryのように動作するプロパティを公開する必要があります。アカウントクラスでユーザー定義のプロパティをサポートする方法の例を次に示します。

public class Account
{
    Dictionary<string, object> properties;
    public object this[string propertyName]
    {
        get
        {
            if (properties.ContainsKey[propertyName])
                return properties[propertyName];
            else
                return null;
        }
        set
        {
            properties[propertyName] = value;
        }
    }
}
1
Paul Williams

Reflectionを使用する必要があります。

PropertyInfo property = typeof(Account).GetProperty("Reference");

property.SetValue(myAccount, "...", null);

これは非常に遅いことに注意してください。

1
SLaks