Деревья выражений: вызов метода с аргументами out или ref - PullRequest
5 голосов
/ 20 мая 2011

Этот код работает в .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 голосов
/ 25 октября 2016

A Ref Аргумент будет управляться классической переменной CLR, которая будет просто Box (инкапсулируется в объект, которому нужно передать элемент по ссылке), если этот является значением.

Out позволяет иметь несколько выходных данных и будет оказывать большее влияние в процессе компиляции.

Выражения компилируются во время выполнения, но валидность out проверяется во время компиляции.

Под валидностью я подразумеваю, что компилятор гарантирует, что метод БУДЕТ НАЗНАЧИТЬ значение параметру out .

0 голосов
/ 24 июня 2011

Вы пытались изменить

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() } );

С уважением,

...