c# - 在转换为 "out/ref"的表达式中支持 "object"参数

标签 c# .net-4.0 delegates function-pointers linq-expressions

我解决这个问题的旅程始于 Jon Skeet 文章的实现:"Making reflection fly and exploring delegates" :

在其中,他说:

Note: I was going to demonstrate this by calling DateTime.AddDays, but for value type instance methods the implicit first first parameter is passed by reference, so we’d need a delegate type with a signature of DateTime Foo(ref DateTime original, double days) to call CreateDelegate. It’s feasible, but a bit of a faff. In particular, you can’t use Func<...> as that doesn’t have any by-reference parameters.

我正在使用自己的委托(delegate)来支持这一点,但我完全无法尝试在 C# .NET 4.0 中创建编译表达式以支持“out/ref”,但将委托(delegate)类型转换为“object”。

当我运行下面的代码时,我在第一种情况下得到了预期的输出,但是,在第二种情况下(当我将输入和输出参数转换为类型:对象时)“out”参数未分配并且结果是“之前”而不是“之后”。

public class Test
    {
        public delegate void myDelegate<T, U>(T test, out U setMe);

        public void myFunction(out string setMe)
        {
            setMe = "after";
        }
    }

private static playin.program.Test.myDelegate<Test, string> buildExactExpression(MethodInfo methodInfo)
    {
        ParameterExpression instance = Expression.Parameter(typeof(Test));
        ParameterExpression argument = Expression.Parameter(typeof(string).MakeByRefType());

        var methodCall = Expression.Call(
                         instance,
                         methodInfo,
                         argument);

        return Expression.Lambda<playin.program.Test.myDelegate<Test, string>>(methodCall, new ParameterExpression[] { instance, argument }).Compile();
    }

    private static playin.program.Test.myDelegate<object, object> buildDesiredExpression(MethodInfo methodInfo)
    {
        ParameterExpression instance = Expression.Parameter(typeof(object));
        ParameterExpression argument = Expression.Parameter(typeof(object).MakeByRefType());

        var methodCall = Expression.Call(
                         Expression.Convert(instance, typeof(Test)),
                         methodInfo,
                         Expression.Convert(argument, typeof(string)));

        return Expression.Lambda<playin.program.Test.myDelegate<object, object>>(methodCall, new ParameterExpression[] { instance, argument }).Compile();
    }

static void Main(string[] args)
    {
        Test t1 = new Test();

        var myFunctionMethodInfo = t1.GetType().GetMethod("myFunction");

        //this one works, the "out" string is set to "after" 
        string someString = "before";
        var compiledExactly = buildExactExpression(myFunctionMethodInfo);

        compiledExactly(t1, out someString);
        Console.WriteLine(someString);


        //the following doesn't return the expected output, the "out" parameter is not set,    "before" is printed
        object someObjectString = "before";
        var compiledObject = buildDesiredExpression(myFunctionMethodInfo);

        compiledObject(t1, out someObjectString);
        Console.WriteLine(someObjectString);
    }

对于我的程序中的某些对象,我在运行时发现它们的方法并且提前不知道参数类型,因此在返回的委托(delegate)中转换为“对象”(buildDesiredExpression 方法)非常重要。我想缓存返回的“打开”委托(delegate),以便我可以在执行期间以最小的性能损失运行它们。

如何修复“buildDesiredExpression”方法以使其正常工作?

最佳答案

你可以做的是创建一个正确类型的局部变量,让被调用的方法设置它,然后设置参数:

ParameterExpression instance = Expression.Parameter(typeof(object));
ParameterExpression argument =
    Expression.Parameter(typeof(object).MakeByRefType());
ParameterExpression argumentVariable = Expression.Parameter(typeof(string));

var methodCall = Expression.Call(
                 Expression.Convert(instance, typeof(Test)),
                 methodInfo,
                 argumentVariable);

var block = Expression.Block(
    new[] { argumentVariable },
    methodCall, Expression.Assign(argument, argumentVariable));

return Expression.Lambda<Test.myDelegate<object, object>>(
    block, new[] { instance, argument }).Compile();

关于c# - 在转换为 "out/ref"的表达式中支持 "object"参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27474754/

相关文章:

c# - 如何异步初始化静态类

c# - 如何从匿名委托(delegate)或 lambda 访问安全关键字段?

c# - 将自定义类的集合添加到 Settings.Settings

c# - 从 Process StandardOutput 获取值

c# - 整数和小数的不同格式

c# - 为什么C#声明常量时不能使用匿名类型?

c# - 如何将 GridColumn 绑定(bind)到 ObservableCollection 的索引值?

c# - 是否有比 C# Action 委托(delegate)更有效的方法来避免这种代码重复?

ios - 未正确调用委托(delegate)方法

c# - 异步触发的事件可以在表单上同步运行吗?