2009-10-30 32 views
3

這裏產生的是什麼,我的意思是:在C#中,可以訪問使用字段名的對象的字段在運行時

我需要能夠替代這種難看的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; 

成像這樣:

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

沒有ConvertStringToObjectField()方法,但我想這樣的事情,如果可能的話。我可以訪問machinePool對象的類代碼,所以我可以添加必要的代碼,但我不確定它可能是什麼代碼,甚至可以在C#中完成。

回答

9

是的,你可以通過反射做到這一點:

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

您還可以創建一個擴展方法,使事情變得更加容易:

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

很好的例子,但不要忘記,彈出一個事實,即反射比直接調用方法要慢約1000倍和非常特殊的情況下,只應該用於就像動態加載DLL時一樣。有時候,反思不是必要的,應該使用一種替代方法(有時不使用)。此鏈接討論性能成本:http://stackoverflow.com/questions/25458/how-costly-is-reflection-really – 2009-10-30 00:54:55

0

是的,可以。下面是一些代碼,當我想要得到的屬性名稱作爲字符串(即,處理PropertyChangedEventHandler)我用,但我不希望使用字符串本身:

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

下面是一些測試代碼,以幫助你的工作通過它:

[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

你可以這樣做:

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

然後使用它像:

machinePool.SetPropertyToValue(attribute.Name, attribute.Value); 
相關問題