内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用
对于属性有GetGetMethod
和GetSetMethod
,这样我可以这样做:
Getter = (Func<S, T>)Delegate.CreateDelegate(typeof(Func<S, T>),
propertyInfo.GetGetMethod());
和
Setter = (Action<S, T>)Delegate.CreateDelegate(typeof(Action<S, T>),
propertyInfo.GetSetMethod());
但是我怎么去解决FieldInfo
?
我不是在寻找GetValue
和SetValue
(这意味着我每次都会调用反射)
Getter = s => (T)fieldInfo.GetValue(s);
Setter = (s, t) => (T)fieldInfo.SetValue(s, t);
但是如果在CreateDelegate
这里有办法?我的意思是,由于作业返回一个值,我可以像处理方法一样处理作业吗?如果有的话,是否有MethodInfo
处理它?换句话说,我该如何传递MethodInfo
设置权限并从成员字段中获取值,CreateDelegate
以便我可以返回一个可以直接读写字段的代理?
Getter = (Func<S, T>)Delegate.CreateDelegate(typeof(Func<S, T>), fieldInfo.??);
Setter = (Action<S, T>)Delegate.CreateDelegate(typeof(Action<S, T>), fieldInfo.??);
我可以构建表达式并编译它,但我正在寻找更简单的东西。最后,如果没有问题的答案,我不介意表达路线,如下所示:
var instExp = Expression.Parameter(typeof(S));
var fieldExp = Expression.Field(instExp, fieldInfo);
Getter = Expression.Lambda<Func<S, T>>(fieldExp, instExp).Compile();
if (!fieldInfo.IsInitOnly)
{
var valueExp = Expression.Parameter(typeof(T));
Setter = Expression.Lambda<Action<S, T>>(Expression.Assign(fieldExp, valueExp), instExp, valueExp).Compile();
}
字段访问不是通过方法(如getter和setter)执行的--它是用IL指令执行的--所以没有什么可以执行的。你必须使用表达式路由来创建一个代码块(实际上是IL),它可以分配给委托。
你可以在运行时编译自己的代码。方法将在第一次调用委托时立即编译。因此,第一个调用将是缓慢的,但任何后续调用都将尽可能快地在.NET中获得,而不需要非托管指针/联合。除了第一个调用之外,委托的速度大约是FieldInfo的500倍。
class DemoProgram { class Target { private int value; } static void Main(string[] args) { FieldInfo valueField = typeof(Target).GetFields(BindingFlags.NonPublic| BindingFlags.Instance).First(); var getValue = CreateGetter<Target, int>(valueField); var setValue = CreateSetter<Target, int>(valueField); Target target = new Target(); setValue(target, 42); Console.WriteLine(getValue(target)); } static Func<S, T> CreateGetter<S, T>(FieldInfo field) { string methodName = field.ReflectedType.FullName + ".get_" + field.Name; DynamicMethod setterMethod = new DynamicMethod(methodName, typeof(T), new Type[1] { typeof(S) }, true); ILGenerator gen = setterMethod.GetILGenerator(); if (field.IsStatic) { gen.Emit(OpCodes.Ldsfld, field); } else { gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Ldfld, field); } gen.Emit(OpCodes.Ret); return (Func<S, T>)setterMethod.CreateDelegate(typeof(Func<S, T>)); } static Action<S, T> CreateSetter<S,T>(FieldInfo field) { string methodName = field.ReflectedType.FullName+".set_"+field.Name; DynamicMethod setterMethod = new DynamicMethod(methodName, null, new Type[2]{typeof(S),typeof(T)},true); ILGenerator gen = setterMethod.GetILGenerator(); if (field.IsStatic) { gen.Emit(OpCodes.Ldarg_1); gen.Emit(OpCodes.Stsfld, field); } else { gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Ldarg_1); gen.Emit(OpCodes.Stfld, field); } gen.Emit(OpCodes.Ret); return (Action<S, T>)setterMethod.CreateDelegate(typeof(Action<S, T>)); } }