我解决这个问题的旅程始于 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/