Question Accéder à la propriété de l'objet sous forme de chaîne et définir sa valeur


J'ai une instance du Account classe. Chaque objet de compte a un propriétaire, une référence, etc.

Une des façons d’accéder aux propriétés d’un compte consiste à utiliser des accesseurs comme

account.Reference;

mais j'aimerais pouvoir y accéder en utilisant des sélecteurs de chaînes dynamiques comme:

account["PropertyName"];

comme en JavaScript. Donc j'aurais account["Reference"] ce qui renverrait la valeur, mais je voudrais aussi pouvoir attribuer une nouvelle valeur après cela comme:

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

J'ai remarqué que je peux utiliser

DataBinder.Eval(account,"Reference") 

pour obtenir une propriété basée sur une chaîne, mais en utilisant ceci, je ne peux pas attribuer une valeur à la propriété.

Une idée sur comment je pourrais faire ça?


30
2018-05-25 13:44


origine


Réponses:


Tout d'abord, évitez d'utiliser ceci; C # est un langage fortement typé, profitez donc des avantages de type sécurité et performance qui accompagnent cet aspect.

Si vous avez une raison légitime pour obtenir et définir la valeur d'une propriété de manière dynamique (en d'autres termes, lorsque le type et / ou le nom de la propriété ne peuvent pas être définis dans le code), vous devrez alors utiliser la réflexion.

La façon la plus en ligne serait la suivante:

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

Cependant, vous pouvez mettre en cache le PropertyInfo objet pour le rendre plus lisible:

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

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

44
2018-05-25 13:47



Vous pouvez essayer de combiner l'indexeur avec la réflexion ...

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);
    }
}

24
2018-05-25 15:20



Si ce sont vos propres objets, vous pouvez fournir un indexeur pour accéder aux champs. Je ne recommande pas vraiment cela, mais cela permettrait ce que vous voulez.

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            
    }
}

Notez que vous perdez la sécurité de type lorsque vous faites cela.


4
2018-05-25 13:56



Si vous utilisez .Net 4, vous pouvez utiliser le mot-clé dynamique maintenant.

dynamic foo = account;
foo.Reference = "124ds4EE2s";

3
2017-09-04 10:29



J'ai utilisé la méthode de réflexion de Richard, mais j'ai élaboré la méthode set pour gérer les autres types utilisés tels que les chaînes de caractères et les valeurs NULL.

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);
        }
    }
}

La fonction SetValue () génère une erreur si la conversion ne fonctionne pas.


3
2018-01-12 05:36



Vous devez utiliser Reflection:

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

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

Notez que ce sera très lent.


1
2018-05-25 13:48



Je suis d'accord avec les affiches précédentes que vous devez probablement utiliser les propriétés. La réflexion est très lente par rapport à l'accès direct à la propriété.

En revanche, si vous devez conserver une liste de propriétés définies par l'utilisateur, vous ne pouvez pas utiliser les propriétés C #. Vous devez faire semblant d'être un Dictionary, ou vous devez exposer une propriété qui se comporte comme un Dictionary. Voici un exemple de la façon dont vous pouvez faire en sorte que la classe Account prenne en charge les propriétés définies par l'utilisateur:

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
2018-05-25 14:03



Personnellement, je préfère travailler avec des méthodes d'extension, voici mon code:

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);
    }
}

1
2017-10-03 13:40