我试图实现类中的所有字段的静态反射。换句话说,我必须使用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;
}
}
现在,我有这两个问题。
我使用type.GetFields(),但MSDN说这是一个反射方法。这意味着编译器在运行时之前不知道类型。我说的对吗?如果是正确的,使用的理由是什么表达式树。据我所知,表达式树可以翻译成
逻辑相同。如果我把一个名为的列表作为参数呢需要包装的字段。换句话说,而不是我只是把字段名作为参数。
public static Dictionary<string, SetterGetter<T>> GetFieldSetterGetterExpressions<T>(IEnumerable<string> fieldNames
显然,列表在编译时是未知的。还是那句话,中国共产党将如何反应?
- 表达式树的输出是在编译时不知道的,它们是在运行时编译的,这是不同的。使用(缓存的)表达式树编译的优点是,在表达式构造和编译期间只执行一次反射提升。从那里,调用结果委托非常快。
- 如果您确定列表只指定类中实际存在的字段,并且您只提供所有字段的一个子集,那么从理论上讲,您可以在一定程度上减少反射对性能的影响。但是您应该记住,您仍然需要FieldInfo实例,这些实例只能使用反射来检索。因此,为每个已知字段调用
GetField
的总价格可能比为所有字段调用GetFields
的总价格还要高。
在编译时设置字段值的最简单方法是将私有字段转换为公共属性。然后,您可以按照自己的意愿设置它们。
这不是对你开玩笑,这是对差异的解释- c#不允许从外部设置字段,除非使用反射API。而且那些API是为运行时设计的,而不是为编译时设计的。
如果你想改变规则,在编译时生成这样的代码(确切地说,在编译后),你应该使用一些第三方库,如PostSharp或Fody。
这就是故事的结尾,只要你使用c#的当前版本或以前的一个版本。