表达式树:使用out或ref参数调用方法

5

这段代码适用于.NET4:

class Program
{
    static void Main( string[] args )
    {
        var fooExpr = Expression.Parameter( typeof( Foo ), "f" );
        var parmExpr = Expression.Parameter( typeof( int ).MakeByRefType(), "i" );
        var method = typeof( Foo ).GetMethod( "Method1" );
        var invokeExpr = Expression.Call( fooExpr, method, parmExpr );
        var delegateType = MakeDelegateType( typeof( void ), new[] { typeof( Foo ), typeof( int ).MakeByRefType() } );
        var lambdaExpr = Expression.Lambda( delegateType, invokeExpr, fooExpr, parmExpr );
        dynamic func = lambdaExpr.Compile();
        int x = 4;
        func( new Foo(), ref x );
        Console.WriteLine( x );
    }

    private static Type MakeDelegateType( Type returnType, params Type[] parmTypes )
    {
        return Expression.GetDelegateType( parmTypes.Concat( new[] { returnType } ).ToArray() );
    }
}

class Foo
{
    public void Method1( ref int x )
    {
        x = 8;
    }
}

这段代码在动态调用时会出现运行时错误:

class Program
{
    static void Main( string[] args )
    {
        var fooExpr = Expression.Parameter( typeof( Foo ), "f" );
        var parmExpr = Expression.Parameter( typeof( int ).MakeByRefType(), "i" );
        var method = typeof( Foo ).GetMethod( "Method1" );
        var invokeExpr = Expression.Call( fooExpr, method, parmExpr );
        var delegateType = MakeDelegateType( typeof( void ), new[] { typeof( Foo ), typeof( int ).MakeByRefType() } );
        var lambdaExpr = Expression.Lambda( delegateType, invokeExpr, fooExpr, parmExpr );
        dynamic func = lambdaExpr.Compile();
        int x = 4;
        func( new Foo(), out x );
        Console.WriteLine( x );
    }

    private static Type MakeDelegateType( Type returnType, params Type[] parmTypes )
    {
        return Expression.GetDelegateType( parmTypes.Concat( new[] { returnType } ).ToArray() );
    }
}

class Foo
{
    public void Method1( out int x )
    {
        x = 8;
    }
}

怎么会这样呢?唯一的区别在于使用ref还是out参数。

错误信息为:"Delegate <OnTheFlyDelegateType> 存在一些无效的参数",没有更多的细节和内部异常。 - JoshL
只是出于好奇,如果在调用站点使用 ref 而不是 out 会发生什么?另外,如果您使用正确的 out 等签名声明委托类型,并尝试静态类型编译的 lambda,会发生什么? - Marc Gravell
哇,奇怪...如果我在调用站点使用'ref'(并保持方法声明中的'out'),那就可以工作了。一个错误吗?编辑-经过再次思考,不是一个错误。只是奇怪的是,在动态构建的委托类型上没有明确的方法来创建一个'out'参数。谢谢Marc。 - JoshL
2个回答

0

Ref参数将由CLR管理,它是一个经典的变量,如果它是值类型,它将被封装成对象(Box),以便通过引用传递元素。

Out允许具有多个输出,并且在编译过程中将产生更大的影响。

表达式在运行时编译,但“out”有效性在编译时检查。

通过有效性,我指的是编译器确保方法将分配值给out参数。


-1

你试过改变了吗?

typeof(int).MakePointerType

而不是:

typeof( int ).MakeByRefType()

在这些行:

var parmExpr = Expression.Parameter( typeof( int ).MakeByRefType(), "i" );
var delegateType = MakeDelegateType( typeof( void ), new[] { typeof( Foo ), typeof( int ).MakeByRefType() } );

敬礼,


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接