2009-10-30 26 views
3

Voici ce que je veux dire:Est-il possible en C# pour accéder aux champs d'un objet en utilisant les noms de champs générés lors de l'exécution

Je dois être en mesure de remplacer ce laide à la recherche du code C#:

if (attribute.Name == "Name") machinePool.Name = attribute.Value; 
else if (attribute.Name == "Capabilities") machinePool.Capabilities = attribute.Value; 
else if (attribute.Name == "FillFactor") machinePool.FillFactor = attribute.Value; 

en quelque chose comme ceci:

machinePool.ConvertStringToObjectField(attribute.Name) = attribute.Value; 

il n'y a pas de méthode ConvertStringToObjectField(), mais je voudrais avoir quelque chose comme cela, si cela est possible. J'ai accès au code de la classe d'objets machinePool, donc je peux ajouter du code nécessaire, mais je ne suis pas sûr du code que ce soit ou est-ce qu'il est même possible de le faire en C#.

Répondre

9

Oui, vous pouvez le faire à travers la réflexion:

var fieldInfo = machinePool.GetType().GetField(attribute.Name); 
fieldInfo.SetValue(machinePool, attribute.Value); 

Vous pouvez également créer une méthode d'extension pour faciliter les choses:

public static void SetField(this object o, string fieldName, object value) 
{ 
    var fi = o.GetType().GetField(fieldName); 
    fi.SetValue(o, value); 
} 
+1

grand exemple, mais ne pas oublier de faire apparaître le fait que la réflexion est d'environ 1000 fois plus lent que d'appeler une méthode directement et doit être utilisé que dans des circonstances très particulières comme quand charger dynamiquement une DLL. Parfois, la réflexion n'est pas nécessaire et une méthodologie alternative doit être utilisée (et parfois non). Ce lien traite des coûts de performance: http://stackoverflow.com/questions/25458/how-costly-is-reflection-really –

0

Oui, vous pouvez. Voici un code que j'utilise quand je veux obtenir les noms de propriété sous forme de chaînes (par exemple, pour gérer un PropertyChangedEventHandler) mais je ne veux pas utiliser les chaînes elles-mêmes:

public static string GetPropertyName<T>(Expression<Func<T, object>> propertyExpression) 
    { 
     Check.RequireNotNull<object>(propertyExpression, "propertyExpression"); 
     switch (propertyExpression.Body.NodeType) 
     { 
      case ExpressionType.MemberAccess: 
       return (propertyExpression.Body as MemberExpression).Member.Name; 
      case ExpressionType.Convert: 
       return ((propertyExpression.Body as UnaryExpression).Operand as MemberExpression).Member.Name; 
     } 
     var msg = string.Format("Expression NodeType: '{0}' does not refer to a property and is therefore not supported", 
      propertyExpression.Body.NodeType); 
     Check.Require(false, msg); 
     throw new InvalidOperationException(msg); 
    } 

Et voici un code de test pour vous aider à travailler à travers elle:

[TestFixture] 
public class ExpressionsExTests 
{ 
    class NumbNut 
    { 
     public const string Name = "blah"; 
     public static bool Surname { get { return false; } } 
     public string Lame; 
     public readonly List<object> SerendipityCollection = new List<object>(); 
     public static int Age { get { return 12; }} 
     public static bool IsMammel { get { return _isMammal; } } 
     private const bool _isMammal = true; 
     internal static string BiteMe() { return "bitten"; } 
    } 

    [Test] 
    public void NodeTypeIs_Convert_aka_UnaryExpression_Ok() 
    { 
     Assert.That(ExpressionsEx.GetPropertyName<NumbNut>(nn => NumbNut.Age), Is.EqualTo("Age")); 
     Assert.That(ExpressionsEx.GetPropertyName<NumbNut>(nn => NumbNut.IsMammel), Is.EqualTo("IsMammel")); 
     Assert.That(ExpressionsEx.GetPropertyName<NumbNut>(nn => NumbNut.Surname), Is.EqualTo("Surname")); 
    } 

    [Test] 
    public void NodeTypeIs_MemberAccess_aka_MemberExpression_Ok() 
    { 
     Assert.That(ExpressionsEx.GetPropertyName<NumbNut>(nn => nn.SerendipityCollection), Is.EqualTo("SerendipityCollection")); 
     Assert.That(ExpressionsEx.GetPropertyName<NumbNut>(nn => nn.Lame), Is.EqualTo("Lame")); 
    } 

    [Test] 
    public void NodeTypeIs_Call_Error() 
    { 
     CommonAssertions.PreconditionCheck(() => ExpressionsEx.GetPropertyName<NumbNut>(nn => NumbNut.BiteMe()), 
              "does not refer to a property and is therefore not supported"); 
    } 

    [Test] 
    public void NodeTypeIs_Constant_Error() { 
     CommonAssertions.PreconditionCheck(() => ExpressionsEx.GetPropertyName<NumbNut>(nn => NumbNut.Name), 
              "does not refer to a property and is therefore not supported"); 
    } 

    [Test] 
    public void IfExpressionIsNull_Error() 
    { 
     CommonAssertions.NotNullRequired(() => ExpressionsEx.GetPropertyName<NumbNut>(null)); 
    } 

    [Test] 
    public void WasPropertyChanged_IfPassedNameIsSameAsNameOfPassedExpressionMember_True() 
    { 
     Assert.That(ExpressionsEx.WasPropertyChanged<NumbNut>("SerendipityCollection", nn => nn.SerendipityCollection), Is.True); 
    } 

    [Test] 
    public void WasPropertyChanged_IfPassedPropertyChangeArgNameIsSameAsNameOfPassedExpressionMember_True() 
    { 
     var args = new PropertyChangedEventArgs("SerendipityCollection"); 
     Assert.That(ExpressionsEx.WasPropertyChanged<NumbNut>(args, nn => nn.SerendipityCollection), Is.True); 
    } 

} 

HTH

Berryl

0

Vous pouvez faire quelque chose comme:

void SetPropertyToValue(string propertyName, object value) 
{ 
    Type type = this.GetType(); 
    type.GetProperty(propertyName).SetValue(this, value, null); 
} 

utiliser ensuite comme:

machinePool.SetPropertyToValue(attribute.Name, attribute.Value);