使用表达式树获取静态类属性的名称和值

时间:2016-02-05 19:23:01

标签: c# reflection expression-trees

我有一个比较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 个答案:

答案 0 :(得分:2)

问题是当您尝试访问Expression中的属性var fieldsOfObj = (ConstantExpression)obj.Expression;时。

MemberExpression主要由两个属性组成:

  • Expression获取字段或属性的包含对象。
  • Member获取要访问的字段或属性。

在第一种情况(_settings.DomainName)中,属性Expression获取包含memberExpression的{​​{1}}对象,属性_settings返回Member指向DomainName。

在第二种情况(MemberInfo)中,属性Settings.DomainName返回null,因为您没有访问实例的属性,而是访问静态属性。在代码中,对象Expression为空,并且在问题出现时就是这样。

您可以查看this question了解详情。

要解决此问题,您可以执行以下操作:

obj

答案 1 :(得分:1)

允许Expression<Func<T>> expression将允许使用任何内容调用您的方法。要真正灵活,为什么不编译并调用该方法?那么你不需要任何这种魔法......

if (expression.Compile()() != newValue)
{
    ....
}