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

时间:2011-05-20 17:18:33

标签: .net c#-4.0 expression-trees

此代码适用于.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参数。

2 个答案:

答案 0 :(得分:0)

一个 Ref 参数将由CLR管理一个经典变量,它只是Box(如果这个值是值,则封装到一个对象中以通过引用传递元素)。

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

表达式是在运行时编译的,但" out"有效性在编译时检查。

根据有效性,我的意思是编译器确保方法将ASSIGN 值为 out 参数。

答案 1 :(得分:-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() } );

此致