2016-02-05 53 views
0

我有一個比較2個屬性的通用方法,如果值不同,它會記錄更改和保存。使用表達式樹獲取靜態類屬性的名稱和值

private void SaveIfChanged<T>(Expression<Func<T>> expression, T newValue) 
      { 

       var expr = (MemberExpression)expression.Body; 
       var obj = (MemberExpression)expr.Expression; 
       var fieldsOfObj = (ConstantExpression)obj.Expression; 
       var valuesOfAllFieldsOfObj = ((FieldInfo)obj.Member).GetValue(fieldsOfObj.Value); 

       var propertyInfo = ((PropertyInfo)expr.Member); 
       var oldPropertyValue = propertyInfo.GetValue(valuesOfAllFieldsOfObj, null); 

       if (oldPropertyValue.Equals(newValue)) return;  


var desctiptionAttributes = (DescriptionAttribute[])propertyInfo.GetCustomAttributes(typeof(DescriptionAttribute), false); 
       Log("{0} changed from {1} to {2}",desctiptionAttributes[0].Description, oldPropertyValue, newValue); 
       propertyInfo.SetValue(valuesOfAllFieldsOfObj, newValue, null); 

       Save(); 
      } 

它工作正常,當我傳遞非靜態類的成員屬性,但是當我傳遞一個靜態屬性,然後它不起作用。

SaveIfChanged(() => _settings.DomainName, DomainName); // Works 
SaveIfChanged(() => Settings.DomainName, DomainName); //Doesn't work 

我也知道如何獲得靜態類的字段/屬性,但只有當我有類名。我只是不知道如何將以下內容與我的方法相結合。

 Type s= typeof(Settings); 
     FieldInfo[] fields = t.GetFields(BindingFlags.Static | BindingFlags.Public); 

     foreach (FieldInfo fi in fields) 
     { 
      Console.WriteLine(fi.Name); 
      Console.WriteLine(fi.GetValue(null).ToString()); 
     } 

謝謝。

回答

2

問題是當您嘗試訪問var fieldsOfObj = (ConstantExpression)obj.Expression;中的屬性Expression時。

MemberExpression主要由兩個屬性:

  • Expression獲得的字段或屬性的包含對象。
  • Member獲取要訪問的字段或屬性。

在第一種情況(_settings.DomainNameExpression得到含有_settings一個memberExpression對象的屬性和屬性Member返回MemberInfo指向域名。

在第二種情況下(Settings.DomainName),屬性Expression返回null,因爲您未訪問實例的屬性,您正在訪問靜態屬性。在代碼中,對象obj爲空,這就是問題出現的時間。

有關詳細信息,請參見this question

爲了解決這個問題,你可以這樣做:

private static void SaveIfChanged<T>(Expression<Func<T>> expression, T newValue) 
{ 
    var expr = (MemberExpression)expression.Body; 

    object valuesOfAllFieldsOfObj = null; 
    if (expr.Expression != null) 
    { 
     var obj = (MemberExpression)expr.Expression; 
     var fieldsOfObj = (ConstantExpression)obj.Expression; 
     valuesOfAllFieldsOfObj = ((FieldInfo)obj.Member).GetValue(fieldsOfObj.Value); 
    } 

    var propertyInfo = ((PropertyInfo)expr.Member); 
    var oldPropertyValue = propertyInfo.GetValue(valuesOfAllFieldsOfObj, null); 

    if (oldPropertyValue.Equals(newValue)) return; 

    var desctiptionAttributes = (DescriptionAttribute[])propertyInfo.GetCustomAttributes(typeof(DescriptionAttribute), false); 
    Log("{0} changed from {1} to {2}", desctiptionAttributes[0].Description, oldPropertyValue, newValue); 
    propertyInfo.SetValue(valuesOfAllFieldsOfObj, newValue, null); 

    Save(); 
} 
+0

完美,這就是我所困惑的。 – Marshal

1

允許Expression<Func<T>> expression將讓你的方法用什麼來調用。爲了非常靈活,爲什麼不編譯和調用該方法?那麼你不需要任何這種魔術......

if (expression.Compile()() != newValue) 
{ 
    .... 
} 
相關問題