2010-06-30 2 views
9

Я пытаюсь создать выражение, которое вызывает внутренний метод, внутренний метод имеет параметр out, возможно ли это?Создать выражение для вызова метода с параметром out

public class Program 
{ 
    static void Main(string[] args) 
    { 
     var type = typeof (Program); 
     var methodInfo = type.GetMethod("ValidateActiveControl", BindingFlags.Instance | BindingFlags.NonPublic); 

     var p1 = Expression.Parameter(type, "program"); 
     var p2 = Expression.Parameter(typeof (bool), "validatedControlAllowsFocusChange"); 

     var invokeExpression = Expression.Call(p1, methodInfo, p2); 
     var func = (Func<Program,bool, bool>)Expression.Lambda(invokeExpression, p1, p2).Compile(); 

     var validatedControlAllowsFocusChange = true; 
     // I would expect validatedControlAllowsFocusChange to be false after execution... 
     Console.WriteLine(func.Invoke(new Program(), validatedControlAllowsFocusChange)); 
     Console.WriteLine(validatedControlAllowsFocusChange); 

    } 

    internal bool ValidateActiveControl(out bool validatedControlAllowsFocusChange) 
    { 
     validatedControlAllowsFocusChange = false; 

     // Some code here... 

     return true; 
    } 
} 

ответ

9

В дополнение к точке Джима о MakeByRefType, вам нужно будет создать пользовательский тип делегата, поскольку Func не поддерживает ref или out. Собираем все вместе:

delegate bool ValidateDelegate(Program program, out bool validatedControlAllowsFocusChange); 

static void Main(string[] args) 
{ 
    var type = typeof(Program); 
    var methodInfo = type.GetMethod("ValidateActiveControl", BindingFlags.Instance | BindingFlags.NonPublic); 

    var p1 = Expression.Parameter(type, "program"); 
    var p2 = Expression.Parameter(typeof(bool).MakeByRefType(), "validatedControlAllowsFocusChange"); 

    var invokeExpression = Expression.Call(p1, methodInfo, p2); 
    var func = Expression.Lambda<ValidateDelegate>(invokeExpression, p1, p2).Compile(); 

    var validatedControlAllowsFocusChange = true; 
    // I would expect validatedControlAllowsFocusChange to be false after execution... 
    Console.WriteLine(func.Invoke(new Program(), out validatedControlAllowsFocusChange)); 
    Console.WriteLine(validatedControlAllowsFocusChange); 

} 

Edit: Это работает в .NET 4.0, но не в .NET 3.5. 3.5 Framework не поддерживает деревья лямбда-выражения с параметрами out или ref. Этот код:

delegate void RefTest(out bool test); 

static void Main(string[] args) 
{ 
    var p1 = Expression.Parameter(typeof(bool).MakeByRefType(), "test"); 
    var func = Expression.Lambda<RefTest>(Expression.Constant(null), p1); 
} 

вызывает исключение ArgumentException «Ярбда-выражение не может содержать проход по опорным параметрам». Я не думаю, что вы можете делать то, что хотите, без обновления до .NET 4.0.

+0

Это все еще вызывает ошибку. Выражение типа «System.Boolean &» не может использоваться для параметра типа «System.Boolean» метода «Boolean ValidateActiveControl (Boolean ByRef)». –

+0

Приятная находка на .NET 4. Лямбда, не проходящая мимо ссылка в 3.5 является серьезным ограничением. –

1

Согласно this blog post, вам нужно сделать:

typeof(bool).MakeByRefType();

+0

Это работает с использованием отражения, когда я создаю выражение, я получаю следующую ошибку. Выражение типа «System.Boolean &» не может использоваться для параметра типа «System.Boolean» метода «Boolean ValidateActiveControl (Boolean ByRef)» –

+0

Извините это не сработало. Эта ошибка кажется очень странным (и ненужным) требованием для лямбда. –

Смежные вопросы