type.GetFields()的静态(表达式)替代方案



我试图实现类中的所有字段的静态反射。换句话说,我必须使用name为所有这些字段创建get和set。

我用表达式树对设置字段值的答案,得出以下解决方案

  public class ExpressionSetterGetter
    {
        public class SetterGetter<T> where T : class
        {
            public Delegate getter;
            public Action<T, object> setter;
        }
        public static Dictionary<string, SetterGetter<T>> GetFieldSetterGetterExpressions<T>() where T : class
        {
            var dic = new Dictionary<string, SetterGetter<T>>();
            SetterGetter<T> setterGetter;
            var type = typeof(T);
            var fields = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
            foreach (var fieldInfo in fields)
            {
                var targetExp = Expression.Parameter(type, "target");
                var valueExp = Expression.Parameter(typeof(object), "value");
                var fieldExp = Expression.Field(targetExp, fieldInfo);
                var assignExp = Expression.Assign(fieldExp, Expression.Convert(valueExp, fieldExp.Type));
                var fieldSetter = Expression.Lambda<Action<T, object>>(assignExp, targetExp, valueExp).Compile();
                ParameterExpression objParm = Expression.Parameter(type, "obj");
                MemberExpression fieldExpr = Expression.Field(objParm, fieldInfo.Name);
                var fieldExprConverted = Expression.Convert(fieldExpr, typeof(object));
                var fieldGetter = Expression.Lambda(fieldExprConverted, objParm).Compile();
                setterGetter = new SetterGetter<T>() { setter = fieldSetter, getter = fieldGetter };
                dic.Add(fieldInfo.Name, setterGetter);
            }
            return dic;
        }
    }

现在,我有这两个问题。

  1. 我使用type.GetFields(),但MSDN说这是一个反射方法。这意味着编译器在运行时之前不知道类型。我说的对吗?如果是正确的,使用的理由是什么表达式树。据我所知,表达式树可以翻译成

  2. 逻辑相同。如果我把一个名为的列表作为参数呢需要包装的字段。换句话说,而不是我只是把字段名作为参数。

    public static Dictionary<string, SetterGetter<T>> GetFieldSetterGetterExpressions<T>(IEnumerable<string> fieldNames

显然,列表在编译时是未知的。还是那句话,中国共产党将如何反应?

  1. 表达式树的输出是在编译时不知道的,它们是在运行时编译的,这是不同的。使用(缓存的)表达式树编译的优点是,在表达式构造和编译期间只执行一次反射提升。从那里,调用结果委托非常快。
  2. 如果您确定列表只指定类中实际存在的字段,并且您只提供所有字段的一个子集,那么从理论上讲,您可以在一定程度上减少反射对性能的影响。但是您应该记住,您仍然需要FieldInfo实例,这些实例只能使用反射来检索。因此,为每个已知字段调用GetField的总价格可能比为所有字段调用GetFields的总价格还要高。

在编译时设置字段值的最简单方法是将私有字段转换为公共属性。然后,您可以按照自己的意愿设置它们。

这不是对你开玩笑,这是对差异的解释- c#不允许从外部设置字段,除非使用反射API。而且那些API是为运行时设计的,而不是为编译时设计的。

如果你想改变规则,在编译时生成这样的代码(确切地说,在编译后),你应该使用一些第三方库,如PostSharp或Fody。

这就是故事的结尾,只要你使用c#的当前版本或以前的一个版本。

相关内容

  • 没有找到相关文章

最新更新