【问题标题】:Get name and value of static class properties using Expression Trees使用表达式树获取静态类属性的名称和值
【发布时间】:2016-02-05 19:23:00
【问题描述】:

我有一个比较 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());
        }

谢谢。

【问题讨论】:

    标签: c# reflection expression-trees


    【解决方案1】:

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

    MemberExpression主要由两个属性组成:

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

    在第一种情况 (_settings.DomainName) 中,属性 Expression 获得一个包含 _settingsmemberExpression 对象,而属性 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();
    }
    

    【讨论】:

    • 完美,这就是我的困惑。
    【解决方案2】:

    允许Expression&lt;Func&lt;T&gt;&gt; expression 将允许你的方法被任何东西调用。要真正灵活,为什么不编译和调用方法呢?那么你就不需要这些魔法了……

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-09-21
      • 1970-01-01
      • 1970-01-01
      • 2012-04-12
      • 1970-01-01
      • 2011-04-01
      相关资源
      最近更新 更多