c# - 有没有办法创建一个委托(delegate)来获取和设置 FieldInfo 的值?

标签 c# delegates expression-trees setvalue fieldinfo

对于属性,有 GetGetMethodGetSetMethod 以便我可以:

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

我不是在寻找 GetValueSetValue 的委托(delegate)(这意味着我每次都会调用反射)

Getter = s => (T)fieldInfo.GetValue(s);
Setter = (s, t) => (T)fieldInfo.SetValue(s, t);

但是如果这里有一个 CreateDelegate 方法呢? 我是说since assignments return a value ,我可以像对待方法一样对待赋值吗? 如果可以,是否有 MethodInfo 句柄?换句话说,我如何将正确的 MethodInfo 设置和从成员字段获取值传递给 CreateDelegate 方法,以便我得到一个委托(delegate),我用它可以直接读写字段吗?

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();
}

或者我是在寻找不存在的东西(因为我还没有看到类似的东西)?

最佳答案

正如 Peter Ritchie 所建议的,您可以在运行时编译自己的代码。一旦您第一次调用委托(delegate),该方法就会被编译。因此第一次调用会很慢,但任何后续调用都将尽可能快地进入 .NET,而无需非托管指针/联合。除第一次调用外,委托(delegate)比直接使用 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>));
    }
}

请记住,结构是按值传递的。这意味着 Action<S, T>如果它作为第一个参数按值传递,则不能用于更改结构的成员。

关于c# - 有没有办法创建一个委托(delegate)来获取和设置 FieldInfo 的值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16073091/

相关文章:

c# - Windows Phone 文本框以只读模式显示插入符

ios - 在项目选择上调用委托(delegate)方法

.net - 使用委托(delegate)会减慢我的 .NET 程序的速度吗?

c# - 多组将 lambda 连接到表达式树

c# - 如何实现时间跨度到字符串的转换?

c# - Web API 2/ token 返回更多信息

c# - 如何在 C# 中包装具有未知数量和类型的参数的 Func<T1...Tn> ?

parsing - Antlr:如果重复列表,我可以以不同的方式重写树吗

c# - 查询和映射复杂对象

c# - 无法在 ASP.NET Core 2.0 中对 .js 文件进行响应压缩