据我所知,无法与Expression树中的引用类型进行交互。 (例如,没有任何内容会发出stind.*
或ldind.*
操作码。
我正在研究一些改写器来解决这个烦恼。因为我正在构建一个新的类型,它将方法体替换为委托调用(以解决CompileToMethod
只能执行无法与新成员交互的静态方法的事实)。对于by-ref和out参数,我想我会用StrongBox<T>
替换它们的用法。
因此,如果我遇到一个方法,其签名看起来像这样::
public class SomeClass
{
public virtual bool SomeMethod(string arg1,ref int arg2)
{
}
}
我生成的覆盖,callbase方法和委托字段将如下所示::
public class SomeClass<1> : SomeClass
{
private static bool SomeMethod<0>(
SomeClass target,string arg1,StrongBox<int> arg2)
{
return call target.SomeMethod(arg1,ref arg2.Value)
}
private Func<SomeClass,string,StrongBox<int>,bool> <0>SomeMethod;
public override bool SomeMethod(string arg1,ref int arg2)
{
StrongBox<int> box = new StrongBox<int>();
box.Value = arg2;
bool retVal = <0>SomeMethod.Invoke(this,arg1,box);
arg2 = box.Value;
return retVal;
}
}
然而,这是执行此转换的相当多的代码,对于每个参数,它引入了很多复杂性。当我执行box.Value = arg2
的设置时会更容易,如果我可以执行类似&box.Value = &arg2
的操作,将其地址分配给arg2的地址。这样,当委托对值字段执行变异时,将转发更改。这样做意味着我不需要有一个变量来保存返回值,我不需要执行参考值更新。
或者,如果有一种方法可以使用表达式树执行ref-by-ref语义,我当然都是耳朵。
答案 0 :(得分:0)
不确定我是否真的理解,但也许这是一个解决方案:
class Program
{
public class SomeClass
{
private readonly int _n;
public SomeClass(int n) { _n = n; }
public virtual bool SomeMethod(string arg1, ref int arg2) {
if (String.IsNullOrWhiteSpace(arg1)) return false;
arg2 += arg1.Length + _n;
return true;
}
}
private delegate bool SomeDelegate(SomeClass that, string arg1, ref int arg2);
static void Main(string[] args) {
var instance = Expression.Parameter(typeof (SomeClass), "that");
var arg1Param = Expression.Parameter(typeof(string), "arg1");
var arg2Param = Expression.Parameter(typeof (int).MakeByRefType(), "arg2");
var someMethodInfo = typeof (SomeClass).GetMethod("SomeMethod");
var lambda = Expression.Lambda<SomeDelegate>(Expression.Call(instance, someMethodInfo, arg1Param, arg2Param), instance, arg1Param, arg2Param);
var someDelegate =lambda.Compile();
var myClass = new SomeClass(2);
var arg1 = "yup";
var arg2 = 1;
var result = someDelegate(myClass, arg1, ref arg2);
if(arg2 != 6) throw new Exception("Bad!");
Console.WriteLine("works...");
}
}
我认为重要的一点是typeof (int).MakeByRefType()
。